FileSystemWatcher

[C#] FileSystemWatcherとマルチスレッドの活用法

FileSystemWatcherは、指定したディレクトリ内のファイルやディレクトリの変更を監視するためのC#クラスです。

これをマルチスレッドと組み合わせることで、効率的にファイルシステムの変更を処理できます。

FileSystemWatcherは、ファイルの作成、削除、変更、リネームなどのイベントをトリガーします。

これらのイベントハンドラ内で、別のスレッドを使用して重い処理を非同期に実行することで、メインスレッドの負荷を軽減し、アプリケーションの応答性を向上させることができます。

例えば、TaskクラスThreadクラスを用いて新しいスレッドを生成し、イベント処理を行うことが一般的です。

FileSystemWatcherとマルチスレッドの組み合わせ

マルチスレッドを使う理由

  • ユーザーインターフェースの応答性を保つため
  • ファイルシステムの変更をリアルタイムで監視する際のパフォーマンス向上
  • 複数のファイル操作を同時に処理することで、全体の処理時間を短縮

イベント処理の非同期化

FileSystemWatcherは、ファイルシステムの変更を監視するためのクラスです。

ファイルの変更が発生すると、イベントが発生します。

これらのイベントを非同期で処理することで、アプリケーションの応答性を向上させることができます。

以下は、FileSystemWatcherを使用した非同期イベント処理のサンプルコードです。

using System;
using System.IO;
using System.Threading.Tasks;
using System.Windows.Forms;
public partial class MyForm : Form
{
    private FileSystemWatcher watcher;
    public MyForm()
    {
        InitializeComponent();
        InitializeFileSystemWatcher();
    }
    private void InitializeFileSystemWatcher()
    {
        watcher = new FileSystemWatcher();
        watcher.Path = @"C:\監視するフォルダ"; // 監視するフォルダのパスを指定
        watcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite;
        watcher.Filter = "*.txt"; // 監視するファイルの種類を指定
        watcher.Changed += OnChanged; // 変更イベントのハンドラを登録
        watcher.EnableRaisingEvents = true; // イベントを有効にする
    }
    private async void OnChanged(object sender, FileSystemEventArgs e)
    {
        await Task.Run(() => 
        {
            // ファイル変更時の処理をここに記述
            Console.WriteLine($"ファイルが変更されました: {e.FullPath}");
        });
    }
}

このコードでは、ファイルが変更されるとOnChangedメソッドが呼び出され、非同期で処理が行われます。

これにより、UIスレッドがブロックされることなく、ユーザーはアプリケーションを操作し続けることができます。

Taskクラスを用いた非同期処理

Taskクラスは、非同期処理を簡単に実装するためのクラスです。

FileSystemWatcherのイベントハンドラ内でTask.Runを使用することで、バックグラウンドで処理を実行できます。

これにより、UIスレッドの負荷を軽減し、アプリケーションのパフォーマンスを向上させることができます。

スレッドプールの活用

スレッドプールは、スレッドの管理を自動化し、効率的にリソースを使用するための仕組みです。

FileSystemWatcherのイベント処理において、スレッドプールを利用することで、必要なときにスレッドを取得し、処理が終わったらスレッドを返却することができます。

これにより、スレッドの生成と破棄にかかるオーバーヘッドを削減できます。

以下は、スレッドプールを使用したサンプルコードです。

private void OnChanged(object sender, FileSystemEventArgs e)
{
    ThreadPool.QueueUserWorkItem(state => 
    {
        // ファイル変更時の処理をここに記述
        Console.WriteLine($"ファイルが変更されました: {e.FullPath}");
    });
}

このように、スレッドプールを活用することで、効率的にファイル変更イベントを処理することが可能です。

応用例

大量のファイル変更を効率的に処理する方法

大量のファイル変更が発生する環境では、FileSystemWatcherを使用して効率的に処理することが重要です。

以下のポイントを考慮することで、パフォーマンスを向上させることができます。

  • バッチ処理: 変更イベントを受け取った際に、すぐに処理を行うのではなく、一定時間内に発生した変更をまとめて処理する。
  • デバウンス機能: 短時間に連続して発生する変更イベントを1回にまとめることで、無駄な処理を減らす。

以下は、デバウンス機能を実装したサンプルコードです。

private DateTime lastChangeTime;
private readonly TimeSpan debounceTime = TimeSpan.FromMilliseconds(500);
private async void OnChanged(object sender, FileSystemEventArgs e)
{
    var now = DateTime.Now;
    if (now - lastChangeTime < debounceTime)
    {
        return; // デバウンス時間内は処理しない
    }
    lastChangeTime = now;
    await Task.Run(() => 
    {
        // 変更処理をここに記述
        Console.WriteLine($"ファイルが変更されました: {e.FullPath}");
    });
}

ファイルのバックアップシステムの構築

FileSystemWatcherを利用して、特定のフォルダ内のファイルを監視し、変更があった場合に自動的にバックアップを作成するシステムを構築できます。

以下の手順で実装できます。

  1. 監視対象のフォルダを指定: FileSystemWatcherを設定し、監視するフォルダを指定します。
  2. 変更イベントの処理: 変更があった場合に、元のファイルをバックアップフォルダにコピーします。

以下は、バックアップシステムのサンプルコードです。

private void OnChanged(object sender, FileSystemEventArgs e)
{
    string backupPath = @"C:\バックアップフォルダ\"; // バックアップ先のパス
    string fileName = Path.GetFileName(e.FullPath);
    string destinationPath = Path.Combine(backupPath, fileName);
    File.Copy(e.FullPath, destinationPath, true); // 上書きコピー
    Console.WriteLine($"バックアップ作成: {destinationPath}");
}

リアルタイムログ監視システムの実装

リアルタイムでログファイルを監視し、変更があった場合に新しいログエントリを表示するシステムを構築できます。

これにより、アプリケーションの動作状況をリアルタイムで把握することが可能です。

  1. ログファイルの監視: FileSystemWatcherを使用して、特定のログファイルを監視します。
  2. 新しいエントリの取得: 変更があった場合に、ファイルの内容を読み込み、新しいエントリを表示します。

以下は、リアルタイムログ監視システムのサンプルコードです。

private long lastReadPosition = 0;
private async void OnChanged(object sender, FileSystemEventArgs e)
{
    if (e.ChangeType == WatcherChangeTypes.Changed)
    {
        using (var stream = new FileStream(e.FullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
        {
            stream.Seek(lastReadPosition, SeekOrigin.Begin);
            using (var reader = new StreamReader(stream))
            {
                string newLine;
                while ((newLine = await reader.ReadLineAsync()) != null)
                {
                    Console.WriteLine(newLine); // 新しいログエントリを表示
                }
                lastReadPosition = stream.Position; // 読み取った位置を更新
            }
        }
    }
}

このように、FileSystemWatcherを活用することで、さまざまな応用例を実現することができます。

まとめ

この記事では、C#のFileSystemWatcherとマルチスレッドを活用したプログラミング手法について詳しく解説しました。

特に、ファイル変更の監視や非同期処理の実装方法、さらには実際の応用例を通じて、効率的なファイル管理システムの構築方法を紹介しました。

これを機に、FileSystemWatcherを利用したアプリケーションの開発に挑戦し、実際のプロジェクトに応用してみてください。

Back to top button