如何在Perl中解决“print()on closed filehandle”错误?

13

我在执行Perl脚本时遇到了这个错误。请告诉我如何在Perl中纠正这个错误。

print() on closed filehandle MYFILE

这是导致错误的代码:

sub return_error
{
    $DATA= "Sorry this page is corrently being updated...<p>";
    $DATA.=  "<A href=\"javascript:history.go(-1)\"> Back </A>";
    open(MYFILE,">/home/abc/xrt/sdf/news/top.html");
    print MYFILE $DATA;
    close(MYFILE);
    exit;
}

我希望现在我已经更加清楚明白了。


1
帖子的标题应该被编辑。它看起来像是一个“Perl错误”! - Alan Haggai Alavi
1
如果Perl的警告消息“在关闭的文件句柄上使用print()”还建议检查文件句柄是否可以打开,那就太方便了。 - Matthew Lock
8个回答

33

当你(或解释器本身因为错误)关闭MYFILE后,你想对其执行一些操作。

根据你的代码示例,问题可能是open并没有真正打开文件,脚本可能没有写入文件的权限。

将你的代码更改为以下内容以查看是否有错误:

open(MYFILE, ">", "/home/abc/xrt/sdf/news/top.html") or die "Couldn't open: $!";
< p > 更新

< p > ysth 指出,-w 并不能很好地检查您是否可以写入文件,它只是“检查模式中的一个相关标志是否设置”。此外,brian d foy 告诉我,我使用的条件处理错误不好。因此,我删除了误导性代码。请使用上面的代码。


-w 选项并不检查您是否可以向文件写入数据,而是仅检查 mode 中的相关标志之一是否已设置。这可能会产生错误的结果。您最好尝试打开文件进行写入,然后检测打开错误。 - ysth
那个if-else的梗是从哪里来的?有人期望$!在else块中是什么吗?这肯定与open无关。 - brian d foy
@ysth @brian 感谢您的评论。我更新了我的答案以反映您的意见。我已经有一段时间没有经常使用 Perl 了,对写作错误感到抱歉。 - viam0Zah

14

看起来open调用失败了。在打开文件句柄时,您应该始终检查状态。

my $file = '/home/abc/xrt/sdf/news/top.html';
open(MYFILE, ">$file") or die "Can't write to file '$file' [$!]\n";
print MYFILE $DATA;
close MYFILE;

如果打开失败,内置变量$!(也称为$OS_ERROR)将包含操作系统相关的错误信息,例如“权限被拒绝”。

对于非古老版本的Perl,最好使用三个参数形式的open和词法文件句柄:

my $file = '/home/abc/xrt/sdf/news/top.html';
open(my $fh, '>', $file) or die "Can't write to file '$file' [$!]\n";
print {$fh} $DATA;
close $fh;

我知道这是PBP的写法,但我就是无法习惯使用 print {$fh} $DATA 来输出到文件句柄。它看起来就是不对劲。 - Telemachus

6

除了使用 or die,另一种解决方案是使用autodie 声明:

#!/usr/bin/perl

use strict;
use warnings;
use autodie;

open my $fh, "<", "nsdfkjwefnbwef";

print "should never get here (unless you named files weirdly)\n";

上面的代码会产生以下错误(除非当前目录中存在名为nsdfkjwefnbwef的文件):
Can't open 'nsdfkjwefnbwef' for reading: 'No such file or directory' at example.pl line 7

3

这个:

open(MYFILE,">/home/abc/xrt/sdf/news/top.html");

现代Perl中,它可以被写成:

open(my $file_fh, ">", "/home/abc/xrt/sdf/news/top.html") or die($!);

这样,您可以获得一个仅限于范围的$variable,如果您有奇怪的文件名(例如以“& gt;”开头),则没有“花哨的事务”,并且具有错误处理功能(您可以使用警告或错误处理代码替换die)。
一旦您关闭$file_fh或简单地退出范围,您将无法再打印到它。

3

当我的文件设置为只读时,我遇到了这个问题。

在放弃之前,请检查这个问题!:)


2

检查打开操作是否成功

if(open(my $FH, ">", "filename") || die("error: $!"))
{
    print $FH "stuff";
    close($FH);
}

2
您不需要 if() 结构。当它为 false 时,您已经挂了。 :) - brian d foy

2
如果您使用全局符号MYFILE作为文件句柄,而不是本地词法变量($myfile),则如果您的程序是多线程的(例如,如果它通过mod_perl运行),您将不可避免地遇到问题。一个进程可能会在另一个进程试图写入它时关闭文件句柄。使用$myfile将避免此问题,因为每个实例都有自己的本地副本,但仍然会遇到一个进程可能覆盖另一个正在写入的数据的问题。在写入时使用flock()锁定文件。

1
在你的脚本中,你将会进行类似以下的操作:
open MYFILE, "> myfile.txt";
# do stuff with myfile
close MYFILE;
print MYFILE "Some more stuff I want to write to myfile";

最后一行会抛出错误,因为MYFILE已经关闭。

更新

看了你的代码之后,似乎你试图写入的文件根本无法打开。正如其他人已经提到的,尝试做类似以下的操作:

open MYFILE, "> myfile.txt" or die "Can't open myfile.txt: $!\n"

这应该给你一些反馈,让你知道为什么无法打开文件。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接