如何用Perl刷新文件?

如何用Perl刷新文件?,perl,file,flush,io-buffering,Perl,File,Flush,Io Buffering,我有一个Perl脚本,它每3秒向现有文件追加一行。此外,还有一个C++应用程序从该文件中读取。 问题是,在脚本完成并关闭文件句柄后,应用程序开始读取文件。为了避免这种情况,我希望在每行追加后刷新。我该怎么做呢?试试: use IO::Handle; $fh->autoflush; 这实际上是作为一种自动冲水的方式发布的,它询问了普遍接受的实现这一点的糟糕方式:-)来自《人与人》杂志: $old_fh = select(OUTPUT_HANDLE); $| = 1; select($old

我有一个Perl脚本,它每3秒向现有文件追加一行。此外,还有一个C++应用程序从该文件中读取。 问题是,在脚本完成并关闭文件句柄后,应用程序开始读取文件。为了避免这种情况,我希望在每行追加后刷新。我该怎么做呢?

试试:

use IO::Handle;
$fh->autoflush;
这实际上是作为一种自动冲水的方式发布的,它询问了普遍接受的实现这一点的糟糕方式:-)

来自《人与人》杂志:

$old_fh = select(OUTPUT_HANDLE);
$| = 1;
select($old_fh);
如果您只想刷新stdout,您可能只需要执行以下操作:

$| = 1;

但是,请查看常见问题解答,了解一个模块的详细信息,该模块为您提供了一个更易于使用的抽象,例如
IO::Handle

PerlDoc中有一篇关于此的文章:

两种解决方案:

  • 使用以下命令取消缓冲输出文件处理程序:
    $|
  • 如果使用的是
    IO::Handle
    或其子类之一,则调用autoflush方法

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


如果您已经输出到filehandle,并且需要确保它到达物理文件,那么您需要使用IO::Handle
flush
sync
方法。

我也遇到过同样的问题,唯一的区别是用新内容反复写入同一文件。“$|=1”和自动刷新的这种关联对我来说很有用:

 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!
祝你好运。
所有建议设置自动刷新的解决方案都忽略了一个基本事实,即大多数现代操作系统都在缓冲文件I/O,而不管Perl在做什么


强制将数据提交到磁盘的唯一可能性是关闭文件


我遇到了同样的困境,ATM,我们有一个问题,日志正在被写入。

< P>一种替代方法是使用Perl脚本和C++程序之间的替代你当前使用的文件。

TL/DR:使用<代码> IO::句柄< /C> >和<代码>冲洗< /C> >方法,如:

use IO::Handle;
$myfile->flush();
首先,你需要决定你想要它的“脸红”程度。缓冲可以有很多层:

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

  • “脏”文件块的文件系统级缓冲。其他程序仍然可以看到这些更改,它们看起来是“编写的”,但如果操作系统或机器崩溃,它们将丢失

  • 写操作的磁盘级写回缓冲。操作系统认为它们被写入磁盘,但磁盘实际上只是将它们存储在驱动器的易失性内存中。如果操作系统崩溃,数据不会丢失,但如果断电,可能会丢失,除非磁盘可以先将数据写入。这是廉价消费型固态硬盘的一个大问题

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

如果只想刷新Perl缓冲区,可以
关闭
文件,
打印
包含
“\n”
的字符串(因为Perl似乎在换行符上刷新),或者

您还可以每次使用
binmode
或使用
$|
使文件句柄无缓冲。这与刷新缓冲句柄不同,因为将一组缓冲写入排队,然后执行一次刷新比写入非缓冲句柄的性能成本要低得多

如果要刷新文件系统写回缓冲区,需要使用系统调用,如
fsync()
,在
O_DATASYNC
模式下打开文件,或使用众多其他选项之一。这是非常复杂的,事实证明


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

以下是答案-真正的答案

停止在进程生命周期内维护此文件的打开文件句柄

开始将文件附加操作抽象为子文件,该子文件以附加模式打开文件,写入文件,然后关闭文件

# 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;
}

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

谢谢。但这对我没有帮助。即使在每行之后冲洗之后,我的C++程序在读入之后也不能读取这行。它只在perl结束其工作后读取。现在如何刷新STDOUT?@Chloe use
$|=1
afaik,关闭文件进行刷新。MYFILE->autoflush(1)在这里应该做什么?
选择(MYFILE)$|=1
?在“basic”perl中没有flush函数,但如果调用
binmode$filehandle
,它将设置
:raw
格式,并且(作为副作用)将进行flush。它工作得很好。不管怎样,如果它在UNX上,你可以为文件系统创建一个命名管道,你可以直接写它。让你的C++程序从一个管道读取(如果代码愚蠢到需要文件名,就写代码< > DEV/STDIN < /代码>)并检查它一次实际上可以读取一行数据——如果它使用块缓冲读取,那么在写入端您将无能为力。“您唯一可以强制将数据提交到磁盘的方法是关闭文件”。关闭文件并不会将其提交到磁盘,操作系统仍然可以自由写回并缓存它。唯一有保证的方法是调用
fsync()
或操作系统的等效文件描述符。否则,它可能会在操作系统崩溃或断电时丢失。另一种(复杂的单行)编写方法是
select((select(OUTPUT_HANDLE),$|=1)[0])
(在