尝试打印到已关闭的文件句柄时没有错误或警告

No error or warning for trying to print to an already closed filehandle

提问人:mak 提问时间:2/26/2021 最后编辑:zdimmak 更新时间:3/2/2021 访问量:454

问:

在下面的小代码中,我没有收到第 [09] 和 [18] 行的错误或警告。我得到的唯一警告是第 [21] 行:

use strict;                                              # [01]
use warnings FATAL => 'unopened';                        # [02]
                                                         # [03]
open(my $outHandleA, ">outputA.txt") or die ("A: $!\n"); # [04] Opened $outHandleA
print $outHandleA "FILE A\n";                            # [05]
close $outHandleA;                                       # [06] Closed $outHandleA
                                                         # [07]
print $outHandleA;                                       # [08]
print $outHandleA "ABC\n";                               # [09] <---
print $outHandleA;                                       # [10]
print "-----";                                           # [11]
                                                         # [12]
open(OUT, ">outputB.txt") or die ("B: $!\n");            # [13] Opened OUT
print OUT "FILE B\n";                                    # [14]
close OUT;                                               # [15] Closed OUT
                                                         # [16]
print OUT;                                               # [17]
print OUT "DEF\n";                                       # [18] <---
print OUT;                                               # [19]
                                                         # [20]
print DOES_NOT_EXIST_HANDLE "GHI\n";                     # [21] Raises a FATAL warning
                                                         # [22]
print "JKL";                                             # [23] Does not reach here (as expected)

但是,行 [09] 和 [18] 是否也应该引发错误或警告,如下所示,因为它已关闭(未打开)?

  • 错误:print() on closed filehandle $outHandleA at printingToClosedHandle.pl line 9.
  • 警告:print() on unopened filehandle $outHandleA at printingToClosedHandle.pl line 9.

这可能是我的 Perl 版本的问题,它是“perl 5,版本 28,subversion 1 (v5.28.1) 为 MSWin32-x64-multi-thread 构建”。此外,这是我在下面得到的程序的输出:

输出 .txt 输出B.txt 标准输出
文件 A 文件 B 格洛布(0xfeb428)格洛布(0xfeb428)-----

上表中的 STDOUT 输出来自第 [08]、[10] 和 [11] 行。请注意,上表中括号 (...) 之间的值可能会随着每次执行而更改。

Perl 警告 文件句柄

评论

0赞 Shawn 2/26/2021
您可能对编译指示感兴趣,而不是尝试发出警告错误。autodie

答:

5赞 zdim 2/26/2021 #1

已打开(初始化)并关闭的文件句柄与根本没有打开的文件句柄之间存在差异;尝试打印给它们会引出不同的警告。perldiag 中的一个“未开封”条目

%s() 在未打开的 %s
上(W 未打开) 尝试对从未初始化的文件句柄执行 I/O 操作。您需要执行 open()、sysopen() 或 socket() 调用,或者从 FileHandle 包中调用构造函数。

关闭的文件句柄上的 print() 条目说

print() on closed filehandle %s
(W closed) 您正在打印的文件句柄在之前的某个时间自行关闭。检查控制流。

不过,他们都收到了警告。

启用单独时,打印到已初始化但随后关闭的文件句柄不会收到警告。use warnings FATAL => 'unopened'

use warnings;
#use warnings FATAL => 'unopened';
use strict;
use feature 'say';

open my $stdout, '>&', *STDOUT;    # a copy

say $stdout "hi";
close $stdout;
say $stdout "to lexical, closed";  # it warns (l.10)

FATAL_warnings_unopened: { 
    no warnings;                   # change to FATAL for 'unopened'
    use warnings FATAL => 'unopened';

    say $stdout "with FATAL to closed fh";      # no warning
    close STDOUT;
    say "with FATAL to STDOUT";                 # no warning

    say NON_EXISTENT_FH "no such filehandle!";  # l.20
};

say STDERR 'done';

这将打印

hi
say() on closed filehandle $stdout at warnings_FATAL.pl line 10.
say() on unopened filehandle NON_EXISTENT_FH at warnings_FATAL.pl line 20.

根据 FATAL 和块内的文件句柄,它确实退出,但没有警告打印在其正上方。第一次这样的印刷品有一个警告。刚刚关闭的打印件也不会收到警告。unopenedNON_EXISTENT_FH$stdoutSTDOUT

如果我们在一开始就取消注释该行(并删除其他行),则根本不会发出打印到闭合句柄的警告。use warnings FATAL...warnings

仔细阅读警告编译指示的文档是有帮助的。简而言之,我建议始终首先单独使用,然后为想要制作的类别添加一个声明(可以在同一声明中添加多个类别)。use warnings;FATAL

评论

0赞 mak 3/1/2021
我现在明白了。如果我不想打开所有警告,但警告我未打开和已经关闭的文件句柄,那么我应该调用:& 。请注意,注释中的 (l.10)l.20 反映了打印到控制台的行号。此外,当您说(并删除其他警告行)时,我假设您指的是 .至于,我应该看看 Perldoc 中的 Duping 文件句柄use warnings FATAL => 'unopened';use warnings FATAL => 'closed';with_FATAL_warnings: { ... };>&
0赞 zdim 3/2/2021
@MakotoWada 是的,所有要点。因此,我们需要(始终)拥有,然后也可以添加那些想要致命的(您可以在一个语句中添加一些,请参阅警告编译指示的文档,为此我在此答案的最底部添加了链接)。至于“dup”-ing,我认为我的另一个答案中的一些链接(关于这个问题)是有用的。use warnings;
0赞 mak 3/3/2021
是的,关于“dup”-ing,在Perl的奇怪行为中提到了将文件句柄变量从STDOUT重新分配给没有undef()的文件(您称之为“我的另一个答案中的链接(关于这个问题))的链接”)。谢谢。
1赞 zdim 3/3/2021
@MakotoWada 是的,这就是我的意思。这种“dup”-ing(以模式打开)是一种制作新的、独立的文件句柄的方法,它是一个副本(首先)。人们通常说“dup”,因为它使用复制文件句柄的 syscall(参见)。我认为这篇文章(该答案中的链接)中有一个有用的示例,我认为这篇文章(来自同一答案中的另一个链接)特别好。>&dup2man 2 dup
3赞 Dave Sherohman 2/26/2021 #2

你违反了它的细节和背后的导入机制。也就是说,如果你 ,那么只会被导入,即使正常导出其他东西。useuse Foo 'bar';Foo::barFoo

以同样的方式,不会打开所有警告。它打开“未打开”警告:use warnings FATAL => 'unopened';

$ perl -E 'use warnings FATAL => "unopened" ; print $x;'
$ perl -E 'use warnings; use warnings FATAL => "unopened" ; print $x;'
Name "main::x" used only once: possible typo at -e line 1.
Use of uninitialized value $x in print at -e line 1.