你啥时候需要在 Perl 中 `END close STDOUT`?

Posted

技术标签:

【中文标题】你啥时候需要在 Perl 中 `END close STDOUT`?【英文标题】:When do you need to `END close STDOUT` in Perl?你什么时候需要在 Perl 中 `END close STDOUT`? 【发布时间】:2011-09-13 08:42:49 【问题描述】:

在tchrists broilerplate 中,我在 END 块中发现了 STDOUT 的显式关闭。

END  close STDOUT 

我知道 END 并关闭,但我不知道为什么需要它。

开始搜索的时候,在perlfaq8找到如下:

例如,您可以使用它来制作 确保您的过滤程序成功 在不填满的情况下完成其输出 磁盘:

END 
    close(STDOUT) || die "stdout close failed: $!";

反正也不明白。 :(

谁能解释一下(也许有一些代码示例):

为什么以及何时需要它 我的 perl 过滤器如何以及在什么情况下会填满磁盘等等。 如果没有它出现问题... 等等??

【问题讨论】:

【参考方案1】:

很多系统都实现了“乐观”的文件操作。我的意思是,调用 print 应该向文件中添加一些数据可以在数据实际写入文件之前成功返回,或者甚至在磁盘上保留足够的空间以使写入成功之前成功返回。

在这些情况下,如果您的磁盘快满了,您的所有打印都可以显示成功,但是当需要关闭文件并将其刷新到磁盘时,系统会意识到没有剩余空间了。然后在关闭文件时出现错误。

此错误意味着您认为已保存的所有输出实际上可能根本没有保存(或部分保存)。如果这很重要,您的程序需要报告错误(或尝试纠正这种情况,或者...)。

所有这些都可能发生在STDOUT 文件句柄上,如果它连接到一个文件,例如如果您的脚本运行为:

perl script.pl > output.txt

如果您输出的数据很重要,并且您需要知道所有数据是否确实写得正确,那么您可以使用您引用的语句来检测问题。例如,在您的第二个 sn-p 中,如果 close 报告错误,则脚本显式调用 die; tchrist's boilerplate 在use autodie 下运行,如果close 失败,它会自动调用die

(虽然这并不能保证数据会永久存储在磁盘上,其他因素也会在那里发挥作用,但这是一个很好的错误指示。即,如果关闭失败,你知道你有问题。)

【讨论】:

@jm666:tchrist 样板的一部分(它来自哪里)是处理错误的use autodie; @jm666,我刚刚尝试用 perl 写入一个完整的磁盘。 Bash 在关闭文件时确实 给出错误,并且它返回零错误代码(成功),而对文件的写入尚未完成!所以 shell 不是我在这里所依赖的。添加 END 子句会使 perl 本身成为正确的警告,并通过 dieing 宣布失败。 @jm666:close STDOUT 的重点不是关闭流,当 perl 进程退出时,无论如何都会发生这种情况。关键是如果close 失败,那么进程将以非零状态码退出,表示失败。这是由use autodie 带来的,或者在您的另一个示例中由close STDOUT || die 完成。 每个脚本都不需要。许多脚本只是将随机信息消息写入标准输出,而不关心它是否连接到任何东西。只有如果写入该文件描述符的数据是重要时才需要,当然并非总是如此。 我保护ENDclose STDOUT 的唯一时间是当我将它送入管道时。即便如此,有时我有一个$SIGPIPE = sub exit 0,而不是一般情况下,过滤程序无法检测到 STDOUT 故障是一个错误。我有时会延迟安装 atexit 处理程序,如eval qqEND close STDOUT 或使用ENDeval close STDOUT 保护它免受autodie 的影响。但是当你有 STDOUT 进入管道时,根据open(STDOUT, "|less"),你当然最好等待它,否则你的父母会在孩子之前退出,搞砸输出。 默认情况下,假设您需要它。【参考方案2】:

我认为马特错了。

Perl 和系统都有缓冲区。 close 导致 Perl 的 缓冲区刷新到系统。正如 Mat 所声称的那样,它不一定会导致 系统的 缓冲区写入磁盘。这就是fsync 所做的。

现在,这无论如何都会在退出时发生,但调用 close 让您有机会处理它在刷新缓冲区时遇到的任何错误。

close 所做的另一件事是在系统尝试将其缓冲区刷新到磁盘时报告早期错误。

【讨论】:

是的 - 明白。恕我直言,将数据保存到内核的 I/O 缓冲区(它们将在下一次“同步”到硬盘时保存)。 (通过更新守护进程,或 launchd(在 OS X 上))

以上是关于你啥时候需要在 Perl 中 `END close STDOUT`?的主要内容,如果未能解决你的问题,请参考以下文章

你啥时候提升项目中的 package.json 版本?

你啥时候在流中使用接口而不是类型别名?

你啥时候在 Go 的 struct 中嵌入互斥锁?

你啥时候使用 Java 的 @Override 注解,为啥?

你啥时候使用“this”关键字? [关闭]

你啥时候想在 C++ 中使用指针和值?