ローカルまたはネットワークドライブの両方でディレクトリに作成されるファイルを監視するアプリケーションをセットアップする必要があります。
FileSystemWatcher
またはタイマーのポーリングが最良のオプションでしょうか。私は過去に両方の方法を使用しましたが、広範囲ではありません。
どちらの方法でもどのような問題(パフォーマンス、信頼性など)がありますか?
実稼働環境とテスト環境でファイルシステム監視が失敗するのを確認しました。今では便利だと思っていますが、信頼できるとは思いません。私のパターンは、ファイルシステムウォッチャーで変更を監視することですが、時々ポーリングして、欠落しているファイルの変更をキャッチします。
編集:UIがある場合、ユーザーにポーリングの代わりに変更を「更新」する機能を与えることもできます。これをファイルシステムウォッチャーと組み合わせます。
私が抱えていた最大の問題は、バッファがいっぱいになったときにファイルが見つからないことです。簡単に修正できます。バッファを増やすだけです。ファイル名とイベントが含まれていることを忘れないでください。予想されるファイルの量(試行とエラー)に増やしてください。ページアウトできないメモリを使用するため、メモリが少なくなると他のプロセスに強制的にページングさせることができます。
バッファに関するMSDNの記事は次のとおりです。 FileSystemWatcher .. ::。InternalBufferSize Property
MSDNごと:
バッファーサイズの増加は、ディスクにスワップアウトできない非ページメモリに起因するため、コストがかかるため、バッファーをできるだけ小さくしてください。バッファオーバーフローを回避するには、NotifyFilterプロパティとIncludeSubdirectoriesプロパティを使用して、不要な変更通知を除外します。
一度に大規模なバッチが予想されるため、16MBを使用します。正常に動作し、ファイルを見逃すことはありません。
また、1つでも処理を開始する前にすべてのファイルを読み取ります...安全にキャッシュされたファイル名を取得し(この場合、データベーステーブルに)、処理します。
ファイルロックの問題については、ファイルがロック解除されるのを1秒、2、4秒など待機するプロセスを生成します。 Weneverポーリング。これは約2年間エラーなしで実稼働されています。
FileSystemWatcher
は、キューに入れられた変更の数が提供されたバッファをオーバーフローした場合、ビジー時間中に変更を見逃すこともあります。これは.NETクラス自体の制限ではなく、基盤となるWin32インフラストラクチャの制限です。私たちの経験では、この問題を最小限に抑える最善の方法は、通知を可能な限り迅速にデキューし、別のスレッドで処理することです。
上記の@ChillTempで述べたように、ウォッチャーはWindows以外の共有では動作しない場合があります。たとえば、マウントされたNovellドライブではまったく機能しません。
折compromise案は、不定期の投票を行って、見逃した変更を拾うことです。
また、ファイルシステムウォッチャーはファイル共有では信頼できないことに注意してください。特に、ファイル共有が非Windowsサーバーでホストされている場合。重要なものにはFSWを使用しないでください。または、不定期にポーリングを使用して、何も見逃していないことを確認する必要があります。
個人的に、私は実動システムでFileSystemWatcher
を使用しましたが、うまく機能しました。過去6か月間、24時間365日稼働するしゃっくりはありませんでした。単一のローカルフォルダー(共有されている)を監視しています。処理する必要があるファイル操作の数は比較的少ない(1日あたり10イベントが発生)。それは私が今まで心配していたものではありません。決定をやり直す必要がある場合は、再度使用します。
現在、平均100ミリ秒ごとに更新されるXMLファイルでFileSystemWatcher
を使用しています。
FileSystemWatcher
が適切に設定されている限り、localファイルで問題が発生することはありません。
リモートファイル監視およびWindows以外の共有に関する経験はありません。
ファイルのポーリングは冗長であり、FileSystemWatcher
に本質的に不信があるか、ここに記載されている他のすべての制限(Windows以外の共有、リモートファイル監視)を直接経験しない限り、オーバーヘッドに値しないと考えます。
ネットワーク共有でFileSystemWatcher
を使用すると問題が発生しました。純粋なWindows環境の場合は問題ないかもしれませんが、NFS共有を監視していました。NFSはステートレスなので、監視しているファイルが変更されたときに通知がありませんでした。
ポーリングに行きます。
ネットワークの問題により、FileSystemWatcher
は信頼できなくなります(エラーイベントをオーバーロードする場合でも)。
ネットワークドライブ上のFSWにいくつかの大きな問題がありました。ファイルを削除すると常にエラーイベントがスローされ、削除されたイベントはスローされませんでした。私は解決策を見つけられなかったので、今ではFSWを避けてポーリングを使用しています。
一方、作成イベントは正常に機能したため、ファイルの作成のみを監視する必要がある場合は、FSWにアクセスできます。
また、共有されているかどうかに関係なく、ローカルフォルダーにはまったく問題がありませんでした。
私の意見では、FSWとポーリングの両方を使用することは時間とリソースの浪費であり、経験豊富な開発者が提案していることに驚いています。 「FSWミス」をチェックするためにポーリングを使用する必要がある場合、当然、FSWを完全に破棄し、ポーリングのみを使用できます。
私は現在、私が開発するプロジェクトにFSWまたはポーリングを使用するかどうかを決定しようとしています。答えを読んで、FSWがニーズを完全にカバーしている場合があることは明らかですが、他の場合には、あなたはneedポーリングをしています。残念ながら、no answerは実際にperformanceの違いに対処しました「任意」)、「信頼性」の問題のみ。質問のその部分に答えることができる人はいますか?
EDIT:nmclean FSWとポーリングの両方を使用することの妥当性のポイント(興味がある場合はコメントの議論を読むことができます)は、 FSWとポーリングの両方を使用すると効率的です。私(および同じ意見を持つ他の人)に光を当ててくれてありがとう、nmclean。
別のスレッドを使用して、できるだけ早くイベントメソッドから戻ることで、問題が解決しました。
private void Watcher_Created(object sender, FileSystemEventArgs e)
{
Task.Run(() => MySubmit(e.FullPath));
}
変更ではなく作成イベントを操作するための実用的なソリューション
コピー、切り取り、貼り付け、移動の場合でも。
class Program
{
static void Main(string[] args)
{
string SourceFolderPath = "D:\\SourcePath";
string DestinationFolderPath = "D:\\DestinationPath";
FileSystemWatcher FileSystemWatcher = new FileSystemWatcher();
FileSystemWatcher.Path = SourceFolderPath;
FileSystemWatcher.IncludeSubdirectories = false;
FileSystemWatcher.NotifyFilter = NotifyFilters.FileName; // ON FILE NAME FILTER
FileSystemWatcher.Filter = "*.txt";
FileSystemWatcher.Created +=FileSystemWatcher_Created; // TRIGGERED ONLY FOR FILE GOT CREATED BY COPY, CUT PASTE, MOVE
FileSystemWatcher.EnableRaisingEvents = true;
Console.Read();
}
static void FileSystemWatcher_Created(object sender, FileSystemEventArgs e)
{
string SourceFolderPath = "D:\\SourcePath";
string DestinationFolderPath = "D:\\DestinationPath";
try
{
// DO SOMETING LIKE MOVE, COPY, ETC
File.Copy(e.FullPath, DestinationFolderPath + @"\" + e.Name);
}
catch
{
}
}
}
静的ストレージを使用したファイル属性変更イベント中のこのFile Watcherのソリューション
class Program
{
static string IsSameFile = string.Empty; // USE STATIC FOR TRACKING
static void Main(string[] args)
{
string SourceFolderPath = "D:\\SourcePath";
string DestinationFolderPath = "D:\\DestinationPath";
FileSystemWatcher FileSystemWatcher = new FileSystemWatcher();
FileSystemWatcher.Path = SourceFolderPath;
FileSystemWatcher.IncludeSubdirectories = false;
FileSystemWatcher.NotifyFilter = NotifyFilters.LastWrite;
FileSystemWatcher.Filter = "*.txt";
FileSystemWatcher.Changed += FileSystemWatcher_Changed;
FileSystemWatcher.EnableRaisingEvents = true;
Console.Read();
}
static void FileSystemWatcher_Changed(object sender, FileSystemEventArgs e)
{
if (e.Name == IsSameFile) //SKIPS ON MULTIPLE TRIGGERS
{
return;
}
else
{
string SourceFolderPath = "D:\\SourcePath";
string DestinationFolderPath = "D:\\DestinationPath";
try
{
// DO SOMETING LIKE MOVE, COPY, ETC
File.Copy(e.FullPath, DestinationFolderPath + @"\" + e.Name);
}
catch
{
}
}
IsSameFile = e.Name;
}
}
これは、複数のトリガーイベントのこの問題に対する回避策です。
特にTDDシナリオでは、ポーリングを使用することをお勧めします。ファイルの存在をモック/スタブするか、ポーリングイベントがトリガーされると、「制御されていない」fswイベントに依存するよりもはるかに簡単だからです。 + fswエラーに悩まされていた多くのアプリで働いていたことに。