1.概要
Windowsで特定のディレクトリを監視して、操作に対するイベントを補足するには
【FileSystemWatcherクラス】を使うのが便利です。
【変更】、【作成】、【削除】、【名前の変更】に対して
それぞれイベントを補足できますが
操作によって挙動が異なるようです。
ここを理解していないと、アプリケーションがエラーを起こしたり
期待する動作にならないことがありますので
今回はこれについて調べてみようかと思います。
2.確認用ソース
動作確認用に下記のサイトのソースを参考にさせて頂きました。
dobon.net
これを少し改造したのが下記のソースになります。
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; namespace FileSystemWatcherTest { class Program { private static System.IO.FileSystemWatcher watcher = null; static void Main(string[] args) { if (watcher != null) return; watcher = new System.IO.FileSystemWatcher(); //監視するディレクトリを指定 watcher.Path = @"C:\work\test"; //最終アクセス日時、最終更新日時、ファイル、フォルダ名の変更を監視する watcher.NotifyFilter = (System.IO.NotifyFilters.LastAccess | System.IO.NotifyFilters.LastWrite | System.IO.NotifyFilters.FileName | System.IO.NotifyFilters.DirectoryName); //すべてのファイルを監視 watcher.Filter = ""; //イベントハンドラの追加 watcher.Changed += new System.IO.FileSystemEventHandler(watcher_Changed); watcher.Created += new System.IO.FileSystemEventHandler(watcher_Changed); watcher.Deleted += new System.IO.FileSystemEventHandler(watcher_Changed); watcher.Renamed += new System.IO.RenamedEventHandler(watcher_Renamed); //監視を開始する watcher.EnableRaisingEvents = true; Console.WriteLine("Wacher Start."); Console.ReadLine(); } private static void watcher_Changed(System.Object source, System.IO.FileSystemEventArgs e) { switch (e.ChangeType) { case System.IO.WatcherChangeTypes.Changed: Console.WriteLine(e.FullPath + ":Changed"); break; case System.IO.WatcherChangeTypes.Created: Console.WriteLine(e.FullPath + ":Created"); bool fileLocked = IsFileLocked(e.FullPath); if (fileLocked) { Console.WriteLine(e.FullPath + ":Locked"); } else { Console.WriteLine(e.FullPath + ":Unlocked"); } break; case System.IO.WatcherChangeTypes.Deleted: Console.WriteLine(e.FullPath + ":Deleted"); break; } } private static void watcher_Renamed(System.Object source, System.IO.RenamedEventArgs e) { Console.WriteLine(e.FullPath + ":Renamed"); } private static bool IsFileLocked(string path) { FileStream stream = null; try { stream = new FileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.None); } catch { return true; } finally { if (stream != null) { stream.Close(); } } return false; } } }
やりたいことは
【C:\work\test】
を監視して、ファイルが作成されたタイミングでファイルにアクセスし
Lockされているかどうか(ファイルの使用中)の確認をしたいと思います。
3.確認方法
下記の3パターンのファイル作成で検証してみます。
①ドラッグアンドドロップ
②【Ctrl + v】でのコピー
③FTPでのファイル転送
使用するファイルは約7MBのmp4ファイルにしました。
4.検証結果
結果は下記のとおりとなりました。
①ドラッグアンドドロップ
Wacher Start. C:\work\test\test.mp4:Created C:\work\test\test.mp4:Unlocked
即時にファイルアクセスが可能でした。
②【Ctrl + v】でのコピー
Wacher Start. C:\work\test\test.mp4:Created C:\work\test\test.mp4:Locked C:\work\test\test.mp4:Changed C:\work\test\test.mp4:Changed
Createdイベントが発生した直後はアクセスが不可で
更にCreatedイベント後にChangedイベントが2回発生しています。
③FTPでのファイル転送
Wacher Start. C:\work\test\test.mp4:Created C:\work\test\test.mp4:Locked C:\work\test\test.mp4:Changed
Createdイベントが発生した直後はアクセスが不可で
更にCreatedイベント後にChangedイベントが1回発生しています。
5.考察
検証結果から、すぐにファイルアクセスするのはやめておいた方がよさそうです。
Createdでイベントを補足し、
別ルーティンで処理がベストかもしれません。
Createdイベント発生後、Changedイベントが発生するのは
まずはファイルを作成してから中身を書き込むという処理が
走っているからだと推測しています。