FileSystemWatcher を使用して新しいファイルのディレクトリを監視する .NET アプリケーションがいくつかあります。ファイルは別の場所からコピーされたり、FTP 経由でアップロードされたりします。ファイルが到着すると、ファイルは何らかの方法で処理されます。ただし、満足のいく答えを見たことがない問題の 1 つは、大きなファイルの場合、監視対象のファイルがまだ書き込まれていることをどのように知ることができるかということです。明らかに、ファイルの処理を開始する前に、ファイルが完了して閉じられるまで待つ必要があります。FileSystemWatcher イベントのイベント引数は、これに対処していないようです。
9 に答える
ファイルをディレクトリに書き込んでいるプログラムを制御している場合は、プログラムにファイルを一時ディレクトリに書き込んでから、それらを監視ディレクトリに移動させることができます。移動はアトミック操作である必要があるため、ファイルがディレクトリに完全に配置されるまで、ウォッチャーはファイルを認識できません。
監視対象ディレクトリへの書き込みを制御できない場合は、ファイルが一定時間同じサイズのままである場合にファイルが完了したとみなされる時間をウォッチャーに設定できます。即時の処理が問題にならない場合、このタイマーを比較的大きな値に設定すると、ファイルが完了しているかどうかを確認するためのかなり安全な方法になります。
FileSystemWatcher の "Changed" イベントは、ファイルが閉じられるまで発生しないはずです。同様の質問に対する私の回答を参照してください。新しいデータが入ってくると、ダウンロード中に FTP ダウンロード メカニズムがファイルを複数回閉じる可能性がありますが、その可能性は少し低いと思います。
ファイルの内容が完全であることを確認できない限り (確認可能な形式であるか、内容のチェックサムが含まれている場合)、ファイル全体が到着したことを確認できるのは送信者だけです。
過去にFTP経由で大きなファイルを送信するためにロック方法を使用しました。
ファイルは別の拡張子で送信され、送信者が満足すると名前が変更されます。
上記は明らかに、一時的な拡張子を持つ古いファイルを定期的に整理するプロセスと組み合わされています。
別の方法として、同じ名前で長さ 0 のファイルを作成し、拡張子 .lck を追加する方法があります。実際のファイルが完全にアップロードされると、lck ファイルは削除されます。受信プロセスは、ロック ファイルの名前を持つファイルを明らかに無視します。
このようなシステムがなければ、受信者はファイル全体が到着したことを確認できません。
x 分間変更されていないファイルをチェックすると、あらゆる種類の問題が発生しやすくなります。
次のメソッドは、書き込み権限でファイルを開こうとします。ファイルがディスクに完全に書き込まれるまで実行をブロックします。
/// <summary>
/// Waits until a file can be opened with write permission
/// </summary>
public static void WaitReady(string fileName)
{
while (true)
{
try
{
using (System.IO.Stream stream = System.IO.File.Open(fileName, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
{
if (stream != null)
{
System.Diagnostics.Trace.WriteLine(string.Format("Output file {0} ready.", fileName));
break;
}
}
}
catch (FileNotFoundException ex)
{
System.Diagnostics.Trace.WriteLine(string.Format("Output file {0} not yet ready ({1})", fileName, ex.Message));
}
catch (IOException ex)
{
System.Diagnostics.Trace.WriteLine(string.Format("Output file {0} not yet ready ({1})", fileName, ex.Message));
}
catch (UnauthorizedAccessException ex)
{
System.Diagnostics.Trace.WriteLine(string.Format("Output file {0} not yet ready ({1})", fileName, ex.Message));
}
Thread.Sleep(500);
}
}
(関連する質問への私の回答から)
ファイルの書き込みロックを取得しようとしましたか? それが書き込まれている場合、それは失敗するはずであり、少しの間そのままにしておくことを知っています...
「file.ext」のプロデューサーにダミーの「file.ext.end」を書き込ませます。
可能であれば file.ext.end シグナルを使用するための +1。file.ext.end の内容は、より大きなファイルのチェックサムです。これはセキュリティのためではなく、途中で文字化けしないようにするためのものです。誰かが自分のファイルを大きなストリームに挿入できる場合は、チェックサムも置き換えることができます。
ファイルのアップロードが途中で失敗し、送信者がまだファイルの再送信 (および再ロック) を試みていない場合、書き込みロックは役に立ちません。
ファイルが ftp によって完全にアップロードされたかどうかを Windows で確認する方法は、ファイルの名前を変更することです。名前の変更に失敗した場合、ファイルは完全ではありません。あまりエレガントではないことは認めますが、機能します。