• 検索結果がありません。

ファイル監視

N/A
N/A
Protected

Academic year: 2021

シェア "ファイル監視"

Copied!
10
0
0

読み込み中.... (全文を見る)

全文

(1)

■ ファイルやディレクトリの監視 ■ ■ FileSystemWatcher クラス

.NET Framework のクラスライブラリには、ファイルやディレクトリの作成・変更・削除を監視する為 のFileSystemWatcher クラスが System.IO 名前空間に用意されて居る(但し、Windows 98/Me では

利用出来ない)。此れを利用すると、特定のディレクトリにファイルが作成された、特定のファイルが 修正されたと謂うタイミングで、其等のファイルに対して何等かの処理を行う様なアプリケーションを 容易に作成する事が出来る。 FileSystemWatcher クラスの利用方法は簡単で、先ず其のインスタンスを作成し、下記の表に示す様な 各プロパティを設定する。 プロパティ 説明 デフォルト値 Path 監視するディレクトリのパス なし IncludeSubdirectories サブディレクトリを監視するか何うかを 示すフラグ false Filter 監視するファイル 総てのファイル(*.*) NotifyFilter 監視する変更の種類(NotifyFilters 列挙 体の値) NotifyFilters.LastWrite NotifyFilters.DirectoryName NotifyFilters.FileName (上記3 個の値の論理和) EnableRaisingEvents 監視を有効にするか何うかを示すフラグ false InternalBufferSize 受け取った通知を格納する内部バッファ のサイズ 8192Bytes(8KBytes) Filter プロパティでは、監視対象と成る特定のファイルを指定する事が出来、*.txt や*.jpg と謂う特定 の種類のファイルも指定可能で有る。 EnableRaisingEvents プロパティを True に設定すると、監視処理が開始される。監視が不要な場合に は、一時的に此のプロパティをFalse に設定すれば良い。 NotifyFilter プロパティでは、監視するディレクトリやファイルの変更の種類を、System.IO 名前空間 のNotifyFilters 列挙体の値の組み合わせ(論理和:C#では|演算子、Visual Basic では Or 演算子を使 用)に依り指定する。 下記に、NotifyFilters 列挙体で定義されて居る値の一覧を示す。 値 説明 Attributes ファイル又はフォルダの属性 CreationTime ファイル又はフォルダが作成された時刻 DirectoryName ディレクトリの名前 FileName ファイルの名前 LastAccess ファイル又はフォルダへの最終アクセス日時 LastWrite ファイル又はフォルダへの最終書き込み日時 Security ファイル又はフォルダのセキュリティ設定 Size ファイル又はフォルダのサイズ

ファ

ァイ

イル

ル操

操作

(2)

NotifyFilter プロパティで指定した項目が変化する時には、下記のイベントが発生する。此の為、通知 を受け度いイベントに関しては、インスタンス作成時に、各イベントに対してイベントハンドラを登録 して置く必要が有る。 イベント イベントの発生するタイミング OnCreated ファイル又はディレクトリが作成された時 OnDeleted ファイル又はディレクトリが削除された時 OnRenamed ファイル又はディレクトリの名前が変更された時 OnChanged サイズ・属性・最終書き込み日時・最終アクセス日時・セキュリティ設定の孰れかが 変更された時 OnError 内部バッファがオーバーフローした時 下記に、FileSystemWatcher クラスを利用した簡単なコード例を示す。 下記のコード例では、C ドライブ配下の総てのディレクトリに対してテキストファイル(拡張子 TXT) の作成と削除を監視し、其等が発生した場合には、其のイベントの種類とファイルのフルパスを表示す る。 Visual Basic Imports System.IO

Public Class FileWatcher

Private Fw As FileSystemWatcher

' 他スレッド(FileSystemWatcher)よりフォームにアクセスする為のデリゲート Delegate Sub WatcherDelegate(ByVal S As String)

' フォームが読み込まれた時の処理

Private Sub FileWatcher_Load(ByVal sender As Object, ByVal e As System.EventArgs) _ Handles Me.Load ' FileSystemWatcher のインスタンス生成 Fw = New System.IO.FileSystemWatcher() End Sub ' フォームが閉じられ様と仕た時の処理

Private Sub FileWatcher_FormClosing(ByVal sender As Object, _

ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing

' FileSystemWatcher のインスタンス破棄 If Fw IsNot Nothing Then

Fw.Dispose( ) End If

End Sub

' ボタン(監視開始)がクリックされた時の処理

Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles btnStart.Click

(3)

' FileSystemWatcher の監視条件設定 Fw.Path = "C:¥" Fw.Filter = "*.txt" Fw.IncludeSubdirectories = True Fw.NotifyFilter = NotifyFilters.FileName ' FileSystemWatcher のイベントハンドラ追加 AddHandler Fw.Created, AddressOf FileWatching AddHandler Fw.Deleted, AddressOf FileWatching ' FileSystemWatcher の監視開始 Fw.EnableRaisingEvents = True End Sub ' ボタン(監視停止)がクリックされた時の処理

Private Sub btnStop_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles btnStop.Click Fw.EnableRaisingEvents = False End Sub ' FileSystemWatcher のイベント処理を行うジェネラルプロシージャ

Private Sub FileWatching(ByVal source As Object, ByVal e As FileSystemEventArgs) ' イベントの種類とフルパスの取得

Dim S As String = e.ChangeType.ToString() & ":" S &= e.FullPath

' リストボックスへの追加

Invoke(New WatcherDelegate(AddressOf ListboxAddItem), S) End Sub

' リストボックスに項目を追加するジェネラルプロシージャ Private Sub ListboxAddItem(ByVal S As String)

' リストボックスへ項目の追加 lstDisp.Items.Add(S) End Sub End Class C# using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.IO;

(4)

namespace FileWatcher {

public partial class FileWatcher : Form { private FileSystemWatcher fw; public FileWatcher( ) { InitializeComponent( ); } // 他スレッド(FileSystemWatcher)よりフォームにアクセスする為のデリゲート delegate void WatcherDelegate(string s);

// フォームが読み込まれた時の処理

private void FileWatcher_Load(object sender, EventArgs e) { // FileSystemWatcher のインスタンス生成 fw = new FileSystemWatcher(); } // フォームが閉じられ様と仕た時の処理

private void FileWatcher_FormClosing(object sender, FormClosingEventArgs e) {

if (fw != null) fw.Dispose(); }

// ボタン(監視開始)がクリックされた時の処理

private void btnStart_Click(object sender, EventArgs e) { // FileSystemWatcher の監視条件設定 fw.Path = @"C:¥"; fw.Filter = "*.txt"; fw.IncludeSubdirectories = true; fw.NotifyFilter = NotifyFilters.FileName; // FileSystemWatcher のイベントハンドラ追加

this.fw.Created += new System.IO.FileSystemEventHandler(this.FileWatching); this.fw.Deleted += new System.IO.FileSystemEventHandler(this.FileWatching); // FileSystemWatcher の監視開始 fw.EnableRaisingEvents = true; } // ボタン(監視停止)がクリックされた時の処理

private void btnStop_Click(object sender, EventArgs e) {

(5)

fw.EnableRaisingEvents = false; }

// FileSystemWatcher のイベント処理を行うジェネラルプロシージャ private void FileWatching(Object sender, FileSystemEventArgs e) { // イベントの種類とフルパスの取得 string s = e.ChangeType.ToString() + ":"; s += e.FullPath; // リストボックスへの追加 Invoke(new WatcherDelegate(ListboxAddItem), s); } // リストボックスに項目を追加するジェネラルプロシージャ private void ListboxAddItem(string s)

{ // リストボックスへ項目の追加 lstDisp.Items.Add(s); } } } イ ベ ン ト を 処 理 す る FileWatching ジ ェネラルプロ シージャ (メソッド) では、 第 2 引数の FileSystemEventArgs クラス(System.IO 名前空間)のオブジェクトから、下記の情報が取得可能で 有る。 名前 説明 ChangeType 発生したイベントの種類を取得する。 FullPath 影響を受けるファイルやディレクトリの絶対パスを取得する。 Name 影響を受けるファイルやディレクトリの名前を取得する。 此のプログラムを実行して、例えば、エクスプローラ上で、C:¥SRC ディレクトリに有る test.txt と謂 うファイルを、C:¥DEST ディレクトリに移動した場合には、下記の様な出力が得られる。 Deleted:c:¥SRC¥test.txt Created:c:¥DEST¥test.txt 更に、移動したファイルを削除した場合には、出力は下記の様に成る。此れは、ファイルが塵埃箱に移 動された事を示して居る。 Deleted:c:¥DEST¥test.txt Created:c:¥recycler¥s-1-5-21-911560763-1030517763-475923621-2261¥dc4.txt ※ FileSystemWatcher オブジェクトは、フォームのスレッドとは別のスレッドで動作する為、当該オ ブジェクトからフォームのコントロールに対して直接操作する事は出来ない。従って、当該オブジ ェクトのインスタンスをコードで生成した場合、一般に、其の結果をフォームの何等かのコントロ ールに表示するWindows アプリケーションでは、デリゲートを使用する必要が有る。此の煩雑さを 解消する為に、次項で説明するFileSystemWatcher コンポーネントが用意されて居る。

(6)

FileSystemWatcher クラスの注意点 リファレンスマニュアルにも有る様に、ファイル作成等の単純と思える操作に関しても、複数のイベン トが発生する場合が有る。此れは、監視対象と成るファイルを作成、変更する外部のアプリケーション の内部動作に依る処も大きい。アプリケーションに依っては、例えば、ファイルの作成時に何度か其の ファイルにアクセスしたり(最終アクセス日時が何度も変化する)、一時ファイルをリネームする事に 依り最終的な出力ファイルを作成したりする場合も有る為で有る。 実アプリケーションで FileSystemWatcher クラスを利用する場合には、発生するイベントを先ず実際 に確認し、必要なNotifyFilter プロパティとイベントの種類を良く吟味する必要が有る。 ■ FileSystemWatcher コンポーネントの利用 上記では、ファイルシステムを監視する為のSystem.IO 名前空間 FileSystemWatcher クラスの基本的 な利用方法に付いて解説した。本項では、Visual Studio.NET 以降(以下、VS.NET 以降)を使用して Windows アプリケーションを作成する場合に、此のクラスを利用する手順に付いて解説する。 VS.NET 以降では、FileSystemWatcher クラスの機能は、ツールボックスのコンポーネントのタブに有 るFileSystemWatcher コンポーネントに纏められて居る。此の為、FileSystemWatcher クラスを使う には、此のコンポーネントをフォーム上にドラッグ&ドロップして配置する丈で有る。 更に、FileSystemWatcher クラスの殆どのプロパティ設定は、プロパティウィンドウで行える。亦、配 置したコンポーネントをダブルクリックすれば、OnChanged イベントに対するイベントハンドラが自 動的に作成される。OnChanged イベント以外のイベントハンドラに付いては、プロパティウィンドウ をイベント一覧に切り替えて選択する事が可能で有る。 猶、FileSystemWatcher クラスの各プロパティやイベントに付いては、前項を参照され度い。 FileSystemWatcher クラスの SynchronizingObject プロパティ Windows アプリケーションで FileSystemWatcher クラスを利用する場合には、注意しなければ成らな いのは、作成や変更が通知されて呼び出されるイベントハンドラのメソッド(以下、FileSystemWatcher イベントハンドラと記述)が、.NET Framework に依り管理されて居るスレッドプール内のスレッドに 依り実行されると謂う事で有る。 此のスレッドは、Windows フォーム上のボタンのクリック等で呼び出される通常のイベントハンドラ が 実 行 さ れ る ス レ ッ ド ( メ イ ン ス レ ッ ド ) と は 別 の ス レ ッ ド で 有 る 。 此 の 為 、 原 則 的 に は FileSystemWatcher イベントハンドラ内でフォーム上のコントロールを操作すると不具合が発生する 可能性が有る(コントロールに対する操作は保証されない)。

但しFileSystemWatcher コンポーネントでは、FileSystemWatcher クラスの SynchronizingObject プ ロパティに依り、其のイベント処理をメインスレッド側で実行する為の仕組みを提供して居る。 FileSystemWatcher コンポーネントを配置した場合には、此の SynchronizingObject プロパティにフ ォーム名(既定では Form1)が指定されて居る。此の場合には、FileSystemWatcher イベントハンド ラはフォームから呼び出される事に成る(正確には、Form クラスの BeginInvoke メソッドが利用され る 。 此 の BeginInvoke メ ソ ッ ド は 何 の ス レ ッ ド か ら も 安 全 に 呼 出 が 可 能 )。 此 の 結 果 、 FileSystemWatcher イベントハンドラはメインスレッド上で実行される事に成る。 猶、FileSystemWatcher イベントハンドラがメインスレッド上で実行されると謂う事は、其のイベント ハンドラで時間の懸かる処理を行うと、ユーザーインターフェイスの反応を悪くして了うと謂う事に繋 がる。Windows アプリケーションで FileSystemWatcher コンポーネントを利用する場合には、此の点 にも注意が必要で有る。

(7)

Visual Basic Public Class FileWatcher

' ボタン(監視開始)がクリックされた時の処理

Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles btnStart.Click ' FileSystemWatcher の監視条件設定 fswFileWatcher.Path = "C:¥" fswFileWatcher.Filter = "*.txt" fswFileWatcher.IncludeSubdirectories = True fswFileWatcher.NotifyFilter = IO.NotifyFilters.FileName ' FileSystemWatcher の監視開始 fswFileWatcher.EnableRaisingEvents = True End Sub ' ボタン(監視停止)がクリックされた時の処理

Private Sub btnStop_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles btnStop.Click ' FileSystemWatcher の監視停止 fswFileWatcher.EnableRaisingEvents = False End Sub

Private Sub fswFileWatcher_Created(ByVal sender As System.Object, _

ByVal e As System.IO.FileSystemEventArgs) Handles fswFileWatcher.Created

' イベントの種類とフルパスの取得

Dim S As String = e.ChangeType.ToString() & ":" S &= e.FullPath

' リストボックスへ項目の追加 lstDisp.Items.Add(S)

End Sub

Private Sub fswFileWatcher_Deleted(ByVal sender As System.Object, _

ByVal e As System.IO.FileSystemEventArgs) Handles fswFileWatcher.Deleted

' イベントの種類とフルパスの取得

Dim S As String = e.ChangeType.ToString() & ":" S &= e.FullPath ' リストボックスへ項目の追加 lstDisp.Items.Add(S) End Sub End Class C# 省略

(8)

■ 監視に依り作成・変更が通知されたファイルを開く 上記で解説したSystem.IO 名前空間の FileSystemWatcher クラスを利用するとファイルの作成や変更 を即座に知る事が出来る。併し、其の通知を受けてファイルの加工や移動を行おうとすると失敗する場 合が有る。本項では、此の様な状況を回避する方法に付いて説明する。 作成や変更のイベントを受けて、直ちにファイルを操作しようと仕た場合に失敗するのは、ファイルの 作成や変更が開始されるタイミングでイベントの通知が発生する為で有る。詰まり、イベントを受け取 った時点では、他のプロセスが未だファイルを作成中や変更中の為、ファイルがロックされた状態で有 ると考えられる。此の様な状況は、当然ファイルのサイズが大きい程、起こり易い。 FileSystemWatcher クラスでは、ファイルの作成や変更の完了を知る事は出来ない為、上記の問題を回 避するには、ファイルがオープン出来る様に成る迄待つと謂うのが1 つの方法で有る。 下記に其の実装例を示す。 Visual Basic Imports System Imports System.IO Public Class FileWatcher Shared Sub Main( )

Dim Fw As FileSystemWatcher = new FileSystemWatcher( )

Fw.Path = "c:¥" Fw.Filter = "*.*"

Fw.IncludeSubdirectories = true

Fw.NotifyFilter = NotifyFilters.FileName

AddHandler watcher.Created, AddressOf FileWatching Fw.EnableRaisingEvents = true

Console.Read( ) ' キー入力が有る迄待機 End Sub

Shared Sub FileWatching (source As object, e As FileSystemEventArgs) Dim St As Stream = Nothing

Dim Cnt As Integer = 10

For I As Integer = 0 To (Cnt - 1) Try

St = File.Open(e.FullPath, FileMode.Open, FileAccess.Read, FileShare.None) If St IsNot Nothing Then

Exit For End If Catch ex As Exception System.Threading.Thread.Sleep(1000) End Try Next

(9)

' St.Close( ) ' ファイルの操作が可能 Else ' タイムアウト End If End Sub End Class C# using System; using System.IO;

public class FileWatchAndOpen { static void Main( )

{

FileSystemWatcher fw = new FileSystemWatcher( );

fw.Path = @"c:¥"; fw.Filter = "*.*";

fw.IncludeSubdirectories = true;

fw.NotifyFilter = NotifyFilters.FileName;

fw.Created += new FileSystemEventHandler(FileWatching); fw.EnableRaisingEvents = true;

Console.Read( ); // キー入力が有る迄待機 }

static void FileWatching (object source, FileSystemEventArgs e) {

Stream st = null; int cnt = 10;

for (int i = 0; i < cnt; 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 {

(10)

// タイムアウト }

} }

此処では、System.IO 名前空間の File クラスの Open メソッドに依りファイルのオープンを試み、失敗

すれば(例外が発生)、1 秒間スリープすると謂う動作を既定回数丈繰り返す。ファイルのオープンが成 功すれば、大抵の場合は、他のプロセスに依る其のファイルへの操作は完了して居ると考えて良い。 勿論、此の様な方法が旨く行くか何うかは、対象と成るファイルを作成や変更して居るアプリケーショ ンの処理方法に依存する。其れが市販アプリケーション等の場合には、実務で利用する前に充分なテス トが必要と成るのは謂う迄も無い。 亦、上記のコードでは待ち時間を合計 10 秒に設定して居るが、作成や変更のイベントが頻繁に発生す る様な場合には、余り待ち時間を長くすると、FileSystemWatcher クラスの内部バッファがオーバーフ ローする可能性が有る。此の様な時には、InternalBufferSize プロパティの値を大きめに設定する等の 対処が必要で有る。

参照

関連したドキュメント

WAV/AIFF ファイルから BR シリーズのデータへの変換(Import)において、サンプリング周波 数が 44.1kHz 以外の WAV ファイルが選択されました。.

画像の参照時に ACDSee Pro によってファイルがカタログ化され、ファイル プロパティと メタデータが自動的に ACDSee

3 主務大臣は、第一項に規定する勧告を受けた特定再利用

• 競願により選定された新免 許人 は、プラチナバンドを有効 活用 することで、低廉な料 金の 実現等国 民へ の利益還元 を行 うことが

(a) ケースは、特定の物品を収納するために特に製作しも

用局面が限定されている︒

い︑商人たる顧客の営業範囲に属する取引によるものについては︑それが利息の損失に限定されることになった︒商人たる顧客は

◎ペルー特恵税率が新たに適用され、それと同時に一般特恵 一般特恵( (GSP GSP) )税率 税率