.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プロパティの値を大きめに設定するなどの対処が必要だ。End of Article

カテゴリ:クラス・ライブラリ 処理対象:ディレクトリ&ファイル
使用ライブラリ:FileSystemWatcherクラス(System.IO名前空間)
使用ライブラリ:Fileクラス(System.IO名前空間)
関連TIPS:
ファイルやディレクトリの作成/変更/削除を監視するには?
 
この記事と関連性の高い別の.NET TIPS
ファイルやディレクトリの作成/変更/削除を監視するには?
Windowsアプリケーションでファイルやディレクトリを監視するには?
オープン中のファイルにアクセスするには?
ファイルをコピー/削除/リネーム/移動するには?
テキスト・ファイルの内容を読み込むには?
このリストは、(株)デジタルアドバンテージが開発した
自動関連記事探索システム Jigsaw(ジグソー) により自動抽出したものです。
generated by

「.NET TIPS」

TechTargetジャパン

Insider.NET フォーラム 新着記事

@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

RSSフィード

キャリアアップ

- PR -
@IT Sepcial

イベントカレンダー

PickUpイベント

- PR -
もっと見る
- PR -

お勧め求人情報

ホワイトペーパーTechTargetジャパン

@IT Sepcial
ソリューションFLASH