既存のファイルに3秒ごとに新しい行を追加するPerlスクリプトがあります。また、そのファイルから読み取るC++アプリケーションがあります。
問題は、スクリプトが実行され、ファイルハンドルが閉じられた後に、アプリケーションがファイルの読み取りを開始することです。これを避けるために、各行を追加した後にフラッシュしたいのですが、Perlが初めてなので、それを行う方法がわかりません。
TL/DR:_IO::Handle
_およびflush
メソッドを使用します。例:
_use IO::Handle;
$myfile->flush();
_
まず、どの程度「フラッシュ」するかを決める必要があります。かなりの数のバッファリング層が存在する可能性があります。
ファイルハンドル上のPerlの内部バッファ。他のプログラムは、このバッファを離れるまでデータを見ることができません。
「ダーティ」ファイルブロックのファイルシステムレベルのバッファリング。他のプログラムでもこれらの変更を見ることができ、「書き込まれた」ように見えますが、OSまたはマシンがクラッシュすると失われます。
書き込みのディスクレベルのライトバックバッファリング。 OSはこれらがディスクに書き込まれていると考えますが、実際にはディスクはドライブ上の揮発性メモリに保存されているだけです。 OSがクラッシュした場合、データは失われませんが、電源が落ちた場合、ディスクが最初にデータを書き込めない場合があります。これは、安価な民生用SSDでは大きな問題です。
SAN、リモートファイルシステム、RAIDコントローラなどが関与すると、さらに複雑になります。パイプ経由で記述している場合、考慮すべきパイプバッファもあります。
Perlバッファーをフラッシュするだけの場合は、close
ファイル、print
_"\n"
_を含む文字列(Perlは改行でフラッシュするように見えるため)、または _IO::Handle
_のflush
メソッドを使用 。
Perl faq ごとにbinmode
を使用するか、_$|
_を使用して、ファイルハンドルをバッファなしにできます。これは、バッファリングされたハンドルをフラッシュするのと同じことではありません。バッファーなしハンドルへの書き込み。
ファイルシステムの書き戻しバッファをフラッシュする場合は、fsync()
などのシステムコールを使用するか、_O_DATASYNC
_モードでファイルを開くか、他の多数のオプションのいずれかを使用する必要があります。 PostgreSQLにはファイル同期メソッドをテストするための独自のツールがあります という事実からもわかるように、これは非常に複雑です。
恒久的ストレージのハードドライブ上に、本当に、本当に、正直であることを確認したい場合は、プログラムのファイルシステムにフラッシュする必要があります。また、OSが要求したときに実際にフラッシュするように、ハードドライブ/ SSD/RAIDコントローラー/ SANなどを設定する必要があります。これは驚くほど複雑で、OS /ハードウェア固有のものです。本当に正しいことを確認するために、「プラグプル」テストを強くお勧めします。
「man perlfaq5」から:
$old_fh = select(OUTPUT_HANDLE);
$| = 1;
select($old_fh);
Stdoutをフラッシュするだけの場合は、おそらく次のようにできます。
$| = 1;
ただし、IO::Handle
などの使いやすい抽象化を提供するモジュールの詳細については、FAQ)を確認してください。
自動フラッシュの設定を提案するすべてのソリューションは、最新のOSのほとんどが、Perlの動作に関係なくファイルI/Oをバッファリングしているという基本的な事実を無視しています。
ファイルを閉じることによってのみ、データをディスクにコミットすることができます。
私は、書き込まれているログのローテーションに問題がある同じジレンマatmに閉じ込められています。
答えは、本当の答えです。
[〜#〜] stop [〜#〜]プロセスの存続期間中、このファイルの開いているファイルハンドルを維持します。
[〜#〜] 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;
}
ファイルを監視するプロセスは、関数が呼び出されるたびに変更される閉じられたファイルに遭遇します。
出力を自動的にフラッシュするには、autoflush/$|
他の人が説明したとおりファイルハンドルに出力する前。
既にファイルハンドルに出力していて、それが物理ファイルに到達することを確認する必要がある場合は、IO :: Handle flush
およびsync
メソッドを使用する必要があります。
PerlDocにこれに関する記事があります:出力ファイルハンドルをフラッシュ/アンバッファーするにはどうすればよいですか?なぜこれを行う必要がありますか?
2つのソリューション:
$|
を使用して、出力ファイルハンドラーをアンバッファーします。IO::Handle
またはそのサブクラスの1つを使用している場合は、autoflushメソッドを呼び出します。別のアプローチは、現在使用しているファイルの代わりに、PerlスクリプトとC++プログラムの間に 名前付きパイプ を使用することです。