C# で 指定ディレクトリ配下 に ファイル生成 されたことを 監視 する方法

0 件のコメント

単純にファイル生成されたかどうかを監視するのであれば FileSystemWathcer を利用するとよいと思います。 ちまたのコードでもそのようなものが多いハズです。

ただ… FileSystemWatcher だけだと、ファイル生成された瞬間にイベントが発生するため、大きなファイルを生成中だとファイルオープンできない問題があります。 なので、ファイル生成された後、開けるようになったらイベント発生させるように少し拡張した 「ファイル生成の監視クラス」 を作ってみました。 …と言っても、イベント発生時に生成されたファイルを開けるかどうかチェックして、無理であれば Timer でもう一度チェックする、といった単純なものです。

目次

仕様

単純には以下のような仕様のものを作ります。

  • 監視するディレクトリが指定できる
  • 監視するディレクトリはサブディレクトリも監視対象にするかどうか指定できる
  • 監視するファイルのフィルタ条件を指定できる
  • ファイル生成されて開けるようになったとき Fireイベント が発生する

ただ、実装上の問題から、 Fireイベント は別スレッドで実行される場合がある、といった注意点があります。

ファイル生成を監視するクラス の サンプルコード

ファイル生成を監視するクラス本体 "FileCreationTrigger"と、イベント発生時に受け渡されるイベント変数 "FileCreationEventArgs" のサンプルコードを以下に掲載します。

FileCreationTrigger.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
namespace garafu
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Timers;
 
    /// <summary>
    /// ファイル生成を監視
    /// </summary>
    public class FileCreationTrigger : IDisposable
    {
        #region ' フィールド
        // ---------------------------------------
        //  フィールド
        // ---------------------------------------
 
        /// <summary>
        /// 監視する対象のフィルタ条件
        /// </summary>
        private string filter = string.Empty;
 
        /// <summary>
        /// サブディレクトリを検索するかどうか
        /// </summary>
        private bool includeSubdirectories = true;
 
        /// <summary>
        /// 監視する間隔
        /// </summary>
        private double interval = 0;
 
        /// <summary>
        /// 監視する対象のフォルダパス
        /// </summary>
        private string path = string.Empty;
 
        /// <summary>
        /// Timerクラスのインスタンス
        /// </summary>
        private Timer timer;
 
        /// <summary>
        /// FileSystemWatcherクラスのインスタンス
        /// </summary>
        private FileSystemWatcher watcher;
 
        /// <summary>
        /// 生成されたファイルでまだイベントを発生させていないファイルのリスト
        /// </summary>
        private List<string> watches = new List<string>();
 
        #endregion
        #region ' コンストラクタ
        // ---------------------------------------
        //  フィールド
        // ---------------------------------------
 
        /// <summary>
        /// FileCreationTrigger クラスのインスタンスを生成、初期化します。
        /// </summary>
        public FileCreationTrigger()
        {
            this.InitializeInstance(null, null, null, null);
        }
 
        /// <summary>
        /// 監視ディレクトリ、監視ファイルのフィルタ条件、サブディレクトリを監視するかどうか を指定して
        /// FileCreationTrigger クラスのインスタンスを生成、初期化します。
        /// </summary>
        /// <param name="path">監視ディレクトリ</param>
        /// <param name="fileter">監視ファイルのフィルタ条件</param>
        /// <param name="includeSubdirectories">サブディレクトリを監視するかどうか</param>
        public FileCreationTrigger(string path, string fileter, bool includeSubdirectories)
        {
            this.InitializeInstance(path, fileter, includeSubdirectories, null);
        }
 
        #endregion
        #region ' イベント
        // ---------------------------------------
        //  イベント
        // ---------------------------------------
 
        /// <summary>
        /// 監視対象ディレクトリに指定されたフィルタに該当するファイルが生成されたとき発生します。
        /// メインスレッドとは別スレッドで動作する場合があります。
        /// </summary>
        public event EventHandler<FileCreationEventArgs> Fire;
 
        #endregion
        #region ' プロパティ
        // ---------------------------------------
        //  プロパティ
        // ---------------------------------------
 
        /// <summary>
        /// 監視対象ファイルのフィルタ条件を取得または設定します。
        /// </summary>
        public string Filter
        {
            get
            {
                return this.filter;
            }
 
            set
            {
                this.filter = value;
                this.watcher.Filter = value;
            }
        }
 
        /// <summary>
        /// サブディレクトリを監視するかどうかを取得または設定します。
        /// </summary>
        public bool IncludeSubdirectories
        {
            get
            {
                return this.includeSubdirectories;
            }
 
            set
            {
                this.includeSubdirectories = value;
                this.watcher.IncludeSubdirectories = value;
            }
        }
 
        /// <summary>
        /// 監視間隔(msec)を取得または設定します。
        /// </summary>
        public double Interval
        {
            get
            {
                return this.interval;
            }
 
            set
            {
                this.interval = value;
                this.timer.Interval = value;
            }
        }
 
        /// <summary>
        /// 監視対象ディレクトリのパスを取得または設定します。
        /// </summary>
        public string Path
        {
            get
            {
                return this.path;
            }
 
            set
            {
                this.path = value;
                this.watcher.Path = value;
            }
        }
        #endregion
        #region ' メソッド
        // ---------------------------------------
        //  メソッド
        // ---------------------------------------
 
        /// <summary>
        /// インスタンスを廃棄します。
        /// </summary>
        public void Dispose()
        {
            this.watcher.Dispose();
            this.timer.Dispose();
        }
 
        /// <summary>
        /// Fireイベントの発生を開始します。
        /// </summary>
        public void Start()
        {
            this.watcher.EnableRaisingEvents = true;
            this.timer.Start();
        }
 
        /// <summary>
        /// Fireイベントの発生を停止します。
        /// </summary>
        public void Stop()
        {
            this.watcher.EnableRaisingEvents = false;
            this.timer.Stop();
        }
 
        /// <summary>
        /// FileSystemWatcherでCreatedイベントが発生したとき実行されます。
        /// </summary>
        /// <param name="sender">呼び出し元インスタンス</param>
        /// <param name="e">イベント引数</param>
        private void FileSystemWatcher_Created(object sender, FileSystemEventArgs e)
        {
            if (this.IsFileLocked(e.FullPath) == false)
            {
                if (this.watches.Contains(e.FullPath))
                {
                    this.watches.Remove(e.FullPath);
                }
 
                this.OnFire(e.FullPath);
            }
            else
            {
                if (this.watches.Contains(e.FullPath) == false)
                {
                    this.watches.Add(e.FullPath);
                }
            }
        }
 
        /// <summary>
        /// インスタンスを初期化します。
        /// </summary>
        /// <param name="path">監視ディレクトリのパス。デフォルトはカレントディレクトリ。</param>
        /// <param name="filter">監視する対象のフィルタ条件。デフォルトはすべてのファイル「*」。</param>
        /// <param name="includeSubdirectories">サブディレクトリを検索するかどうかデフォルトは true。</param>
        /// <param name="interval">監視する間隔(msec)。デフォルトは 1000 ミリ秒。</param>
        private void InitializeInstance(string path, string filter, bool? includeSubdirectories, double? interval)
        {
            // インスタンス生成
            this.watcher = new FileSystemWatcher();
            this.timer = new Timer();
 
            // 初期設定
            this.Path = string.IsNullOrEmpty(path) ? Environment.CurrentDirectory : path;
            this.Filter = string.IsNullOrEmpty(filter) ? "*" : filter;
            this.IncludeSubdirectories = includeSubdirectories.GetValueOrDefault(true);
            this.Interval = interval.GetValueOrDefault(1000);
 
            // イベントのアタッチ
            this.watcher.Created += new FileSystemEventHandler(this.FileSystemWatcher_Created);
            this.timer.Elapsed += new ElapsedEventHandler(this.Timer_Elapsed);
        }
 
        /// <summary>
        /// 指定されたファイルがロックされているかどうかを返します。
        /// </summary>
        /// <param name="path">検証したいファイルへのフルパス</param>
        /// <returns>ロックされているかどうか</returns>
        private 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;
        }
 
        /// <summary>
        /// Fireイベントを発生させます。
        /// </summary>
        /// <param name="fullpath">イベント発生源となったファイルへのフルパス</param>
        private void OnFire(string fullpath)
        {
            if (this.Fire != null)
            {
                this.Fire(this, new FileCreationEventArgs(fullpath));
            }
        }
 
        /// <summary>
        /// TimerでElapsedイベントが発生したとき実行されます。
        /// </summary>
        /// <param name="sender">呼び出し元インスタンス</param>
        /// <param name="e">イベント引数</param>
        private void Timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            foreach (var fullpath in this.watches)
            {
                if (this.IsFileLocked(fullpath) == false)
                {
                    this.watches.Remove(fullpath);
                    this.OnFire(fullpath);
                }
            }
        }
 
        #endregion
    }
}

FileCreationEventArgs.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
namespace garafu
{
    using System;
 
    /// <summary>
    /// ファイル生成
    /// </summary>
    public class FileCreationEventArgs : EventArgs
    {
        /// <summary>
        /// 生成されたファイルへのフルパスを取得します。
        /// </summary>
        public string FullPath { get; private set; }
 
        /// <summary>
        /// パス情報を指定して、FileCreationEventArgs クラスのインスタンスを生成、初期化します。
        /// </summary>
        /// <param name="fullpath">パス情報</param>
        public FileCreationEventArgs(string fullpath)
        {
            this.FullPath = fullpath;
        }
    }
}

ファイル生成を監視するクラス の 利用例

ファイル生成を監視するクラスの利用方法は、インスタンス生成して Fireイベント に イベントハンドラ を接続し、 Startメソッド を呼び出すだけです。 以下にサンプルコードを掲載します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
namespace WpfApplication1
{
    using System;
    using System.IO;
    using System.Windows;
    using garafu;
     
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        private FileCreationTrigger trigger;
 
        public MainWindow()
        {
            this.InitializeComponent();
             
            this.trigger = new FileCreationTrigger();
            this.trigger.Fire += new EventHandler<FileCreationEventArgs>(this.Trigger_Fire);
            this.trigger.Start();
        }
 
        private void Trigger_Fire(object sender, FileCreationEventArgs e)
        {
            // ファイル生成されたときの処理
        }
    }
}

最後に… このブログに興味を持っていただけた方は、 ぜひ 「Facebookページ に いいね!」または 「Twitter の フォロー」 お願いします!!