|   | 
          
 
            
|  
              
 .NET TIPS 
監視により作成/変更が通知されたファイルを開くには?
デジタルアドバンテージ 遠藤 孝信 
2005/04/01 | 
  | 
          
 
            
 
              
 
             | 
        
   「TIPS:ファイルやディレクトリの作成/変更/削除を監視するには?」で解説したFileSystemWatcherクラス(System.IO名前空間)を利用するとファイルの作成や変更を即座に知ることができる。しかし、その通知を受けてファイルを加工したり移動したりしようとすると失敗する場合がある。本稿では、このような状況を回避する方法について紹介する。
 作成や変更のイベントを受けて、すぐファイルを操作しようとした場合に失敗するのは、ファイルの作成や変更が開始されるタイミングでイベントの通知が発生するためだ。つまり、イベントを受け取った時点では、ほかのプロセスがまだファイルを作成中あるいは変更中のため、ファイルがロックされた状態であると考えられる。このような状況は、当然ファイルのサイズが大きいほど起こりやすい。
 FileSystemWatcherクラスではファイルの作成や変更の「完了」を知ることはできないため、上記の問題を回避するには、ファイルがオープンできるようになるまで待つというのが1つの方法だ。
 以下にその実装例を示す。
// watchopen.cs 
 
using System; 
using System.IO; 
 
public class FileWatchAndOpen { 
  static void Main() { 
 
    FileSystemWatcher watcher = new FileSystemWatcher(); 
 
    watcher.Path = @"c:\"; 
    watcher.Filter = "*.*"; 
    watcher.IncludeSubdirectories = true; 
    watcher.NotifyFilter = NotifyFilters.FileName; 
    watcher.Created += new FileSystemEventHandler(DoWork); 
    watcher.EnableRaisingEvents = true; 
 
    Console.Read(); // キー入力があるまで待つ 
  } 
 
  static void DoWork(object source, FileSystemEventArgs e) { 
    Stream st = null; 
    int maxCount = 10; 
 
    for (int i = 0; i < maxCount; i++) { 
      try { 
        if ((st = File.Open( 
              e.FullPath, 
              FileMode.Open, 
              FileAccess.Read, 
              FileShare.None)) != null) { 
          break; 
        } 
      } catch { 
        System.Threading.Thread.Sleep(1000); 
      } 
    } 
    if (st != null) { 
      // st.Close(); 
      // ファイルの操作が可能 
    } else { 
      // タイムアウト 
    } 
  } 
} 
 
// コンパイル方法:csc watchopen.cs
 | 
 
 
 | 
 
| ファイルの作成を監視し、そのファイルが利用可能になるのを待つC#のサンプル・プログラム(watchopen.cs) | 
| 
 | 
 
' watchopen.vb 
 
Imports System 
Imports System.IO 
 
Public Class FileWatcher 
  Shared Sub Main() 
    Dim watcher As FileSystemWatcher = new FileSystemWatcher() 
 
    watcher.Path = "c:\" 
    watcher.Filter = "*.*" 
    watcher.IncludeSubdirectories = true 
    watcher.NotifyFilter = NotifyFilters.FileName 
    AddHandler watcher.Created, AddressOf DoWork 
    watcher.EnableRaisingEvents = true 
 
    Console.Read() ' キー入力があるまで待つ 
  End Sub 
 
  Shared Sub DoWork(source As object, e As FileSystemEventArgs) 
    Dim st As Stream = Nothing 
    Dim maxCount As Integer = 10 
 
    Dim i As Integer 
    For i = 0 To maxCount - 1 
      Try 
        st = File.Open(e.FullPath, FileMode.Open, FileAccess.Read, FileShare.None) 
        If Not st Is Nothing Then 
          Exit For 
        End If 
      Catch ex As Exception 
        System.Threading.Thread.Sleep(1000) 
      End Try 
    Next 
    If Not st Is Nothing Then 
      ' st.Close() 
      ' ファイルの操作が可能 
    Else 
      ' タイムアウト 
    End If 
  End Sub 
End Class 
 
' コンパイル方法:vbc /r:System.dll watchopen.vb
 | 
 
 
 | 
 
| ファイルの作成を監視し、そのファイルが利用可能になるのを待つVB.NETのサンプル・プログラム(watchopen.vb) | 
| 
 | 
 ここでは、Fileクラス(System.IO名前空間)のOpenメソッドによりファイルのオープンを試み、失敗したら(例外が発生したら)1秒間スリープするという動作を既定回数だけ繰り返す。ファイルのオープンが成功すれば、たいていの場合は、ほかのプロセスによるそのファイルへの操作は完了していると考えてよいだろう。
 もちろんこのような方法がうまくいくかどうかは、対象となっているファイルを作成あるいは変更しているアプリケーションの処理方法に依存する。それが市販アプリケーションなどの場合には、実務で利用する前に十分なテストが必要となるのはいうまでもない。
 また、上記のコードでは待ち時間を合計10秒に設定しているが、作成や変更のイベントが頻繁に発生するような場合には、あまり待ち時間を長くしてしまうとFileSystemWatcherクラスの内部バッファがオーバーフローしてしまう可能性がある。このようなときにはInternalBufferSizeプロパティの値を大きめに設定するなどの対処が必要だ。
          
 
            
カテゴリ:クラス・ライブラリ 処理対象:ディレクトリ&ファイル 
使用ライブラリ:FileSystemWatcherクラス(System.IO名前空間) 
使用ライブラリ:Fileクラス(System.IO名前空間) 
              関連TIPS:ファイルやディレクトリの作成/変更/削除を監視するには? | 
        
 
        
 
|  
 | 
 
generated by  
 | 
 
 
 | 
 
 
	
		Insider.NET 記事ランキング
		
		
			本日
			月間