如何在Perl中刷新文件?

时间:2010-12-27 12:52:25

标签: perl file flush io-buffering

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

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

9 个答案:

答案 0 :(得分:30)

尝试:

use IO::Handle;
$fh->autoflush;

这实际上是在an early question of mine中发布的一种自动刷新方式,它询问了普遍接受的实现此方法的不良方法: - )

答案 1 :(得分:25)

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

use IO::Handle;
$myfile->flush();

首先,你需要决定你想要的“冲洗”程度。可以有很多层缓冲:

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

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

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

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

如果您只想刷新Perl缓冲区,可以close文件,print包含"\n"的字符串(因为看起来Perl在换行符上刷新)或{{ 3}}

您还可以按use IO::Handle's flush method使用binmode或使用$|来使文件句柄无缓冲。这与刷新缓冲句柄的不一样,因为排队一堆缓冲写然后执行单次刷新比写入无缓冲句柄的性能成本低得多。

如果要刷新文件系统回写缓冲区,则需要使用fsync()之类的系统调用,以O_DATASYNC模式打开文件,或使用众多其他选项之一。令人痛苦地复杂化,the perl faq

这一事实证明了这一点

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

答案 2 :(得分:15)

来自'man perlfaq5':

$old_fh = select(OUTPUT_HANDLE);
$| = 1;
select($old_fh);

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

$| = 1;

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

答案 3 :(得分:2)

所有建议设置autoflush的解决方案都忽略了这样一个基本事实:大多数现代操作系统都在缓冲文件I / O,而不管Perl正在做什么。

只有通过关闭文件才能强制将数据承诺到磁盘。

我陷入了同样的困境,我们遇到了正在编写的日志轮换问题。

答案 4 :(得分:2)

这是答案,真正的答案。

停止在整个过程中维护此文件的打开文件句柄。

START 将文件追加操作抽象为一个以附加模式打开文件的子文件,写入文件,关闭它。

#appends a new line to the existing file
sub append_new_line{
    my $linedata = shift;
    open my $fh, '>>', $fnm or die $!; # $fnm is file-lexical or something
    print $fh $linedata,"\n"; # flavor to taste
    close $fh;
}

观察文件的过程将遇到一个关闭的文件,无论何时调用该函数都会被修改。

答案 5 :(得分:1)

在PerlDoc中有一篇关于此内容的文章: How do I flush/unbuffer an output filehandle? Why must I do this?

两种解决方案:

  • 使用:$|
  • 取消缓冲输出文件处理程序
  • 如果您使用IO::Handle或其中一个子类,请调用autoflush方法。

答案 6 :(得分:1)

要自动刷新输出,您可以在输出到文件句柄之前按其他人的描述设置autoflush / $|

如果您已经输出到文件句柄并且需要确保它到达物理文件,则需要使用IO :: Handle flushsync方法。

答案 7 :(得分:0)

另一种方法是在您的Perl脚本和C ++程序之间使用named pipe,代替您当前使用的文件。

答案 8 :(得分:-1)

我遇到了同样的问题,即用新内容一遍又一遍地写同一个文件的唯一区别。这个“$ | = 1”和autoflush的关联对我有用:

 open  (MYFILE, '>', '/internet/web-sites/trot/templates/xml_queries/test.xml');
 $| = 1; # Before writing!
 print  MYFILE "$thisCardReadingContentTemplate\n\n";
 close (MYFILE);
 MYFILE->autoflush(1); # After writing!
祝你好运。 ħ