如何在Perl中刷新文件?

Mih*_*yan 23 perl file flush io-buffering

我有Perl脚本,每隔3秒就会在现有文件中添加一行新内容.此外,还有一个从该文件中读取的C++应用程序.

问题是应用程序在脚本完成并且文件句柄关闭后开始读取文件.为了避免这种情况,我想在每行附加后刷新,但我是Perl的新手,不知道该怎么做.

pax*_*blo 31

尝试:

use IO::Handle;
$fh->autoflush;
Run Code Online (Sandbox Code Playgroud)

这实际上是作为一种在我的早期问题中自动刷新的一种方式发布的,它询问了普遍接受的实现这一目标的坏方法:-)


Cra*_*ger 27

TL/DR:使用IO::Handleflush方法,例如:

use IO::Handle;
$myfile->flush();
Run Code Online (Sandbox Code Playgroud)

首先,你需要决定你想要它的"冲洗"程度.可以有很多层缓冲:

  • Perl文件句柄上的内部缓冲区.其他程序在离开此缓冲区之前无法查看数据.

  • 文件系统级缓冲"脏"文件块.其他程序仍然可以看到这些变化,它们似乎是"书面"的,但如果操作系统或机器崩溃,它们将会丢失.

  • 写入的磁盘级回写缓冲.操作系统认为这些是写入磁盘的,但磁盘实际上只是将它们存储在驱动器的易失性存储器中.如果操作系统崩溃,数据不会丢失,但如果电源出现故障,除非磁盘可以先将其写出来.对于廉价的消费者SSD来说,这是一个大问题.

当涉及SAN,远程文件系统,RAID控制器等时,它变得更加复杂.如果您通过管道写入,还需要考虑管道缓冲区.

如果你只是想刷新Perl的缓冲区,你可以close将文件,print包含字符串"\n"(因为它似乎是Perl的换行符刷新),或使用IO::Handleflush方法.

你也可以根据perl faq使用binmode或者使用$|来使文件句柄无缓冲.这是不是一回事作为冲洗缓冲处理,因为排队了一堆缓冲写入然后做一个单一的冲水比写入一个缓冲的手柄低得多的性能开销.

如果要刷新文件系统写回缓冲区,则需要使用系统调用,例如fsync(),在O_DATASYNC模式下打开文件,或使用众多其他选项之一.令人痛苦的复杂,事实证明PostgreSQL有自己的工具来测试文件同步方法.

如果你想确保它真的,真实地,诚实地在永久存储器中的硬盘驱动器上,你必须将它刷新到程序中的文件系统.您还需要配置硬盘驱动器/ SSD/RAID控制器/ SAN /在操作系统要求时真正刷新的任何内容.这可能会非常复杂,并且特定于OS /硬件.强烈建议使用"插拔式"测试,以确保您确实做到了.


Jus*_*ins 15

来自'man perlfaq5':

$old_fh = select(OUTPUT_HANDLE);
$| = 1;
select($old_fh);
Run Code Online (Sandbox Code Playgroud)

如果你只是想刷新标准输出,你可能只是这样做:

$| = 1;
Run Code Online (Sandbox Code Playgroud)

但请查看常见问题解答,了解有关模块的详细信息,该模块可为您提供更好用的抽象,例如IO::Handle.