C#教程

关注公众号 jb51net

关闭
首页 > 软件编程 > C#教程 > C# FileSystemWatcher监听文件

C#通过FileSystemWatcher监听文件的实战技巧

作者:墨瑾轩

在C#中,FileSystemWatcher 是一个“低调的高手”,本文小编将为大家详细介绍一下C#如何通过FileSystemWatcher进行文件监听,感兴趣的小伙伴可以了解下

文件监听的“潜伏”哲学

“监听不是监视,而是‘无感介入’。”

在C#中,FileSystemWatcher 是一个“低调的高手”——它不喧哗,却能实时捕捉文件系统的每一个细微变化(创建、修改、删除、重命名)。但它的“潜伏”能力远不止表面那么简单:从资源优化跨平台兼容,从事件过滤高性能监控,本文将通过真实代码深度解析,带你解锁FileSystemWatcher的“潜伏”技巧,让你的程序在文件系统中如鱼得水。

第一章:FileSystemWatcher的“潜伏”本质

1.1 核心机制:操作系统驱动的监听

FileSystemWatcher 依赖于 Windows 的底层 API(ReadDirectoryChangesW),通过操作系统事件通知机制实现零轮询的高效监听。

代码示例:基础监听器配置

using System;
using System.IO;

class Program
{
    static void Main()
    {
        // 创建监听器实例
        FileSystemWatcher watcher = new FileSystemWatcher();

        // 设置监听目录
        watcher.Path = @"C:\Your\Target\Directory"; // 替换为你的目标路径

        // 设置监听的文件类型(过滤器)
        watcher.Filter = "*.log"; // 仅监控 .log 文件
        watcher.IncludeSubdirectories = true; // 是否包含子目录

        // 注册事件处理
        watcher.Created += OnChanged; // 文件创建
        watcher.Changed += OnChanged; // 文件修改
        watcher.Deleted += OnChanged; // 文件删除
        watcher.Renamed += OnRenamed; // 文件重命名

        // 启动监听
        watcher.EnableRaisingEvents = true;

        // 防止主线程退出
        Console.WriteLine("按任意键退出...");
        Console.ReadKey();
    }

    // 通用事件处理函数
    private static void OnChanged(object source, FileSystemEventArgs e)
    {
        Console.WriteLine($"【{e.ChangeType}】文件: {e.FullPath}");
    }

    // 重命名事件处理
    private static void OnRenamed(object source, RenamedEventArgs e)
    {
        Console.WriteLine($"【重命名】{e.OldName} -> {e.NewName}");
    }
}

关键注释

1.2 性能对比:轮询 VS 事件驱动

方法资源占用响应速度适用场景
轮询简单脚本、小型项目
FileSystemWatcher实时高性能监控、大型系统

代码示例:轮询 VS FileSystemWatcher

// 轮询方式(低效)
while (true)
{
    if (File.Exists("target.txt"))
    {
        Console.WriteLine("文件已创建!");
        break;
    }
    Thread.Sleep(1000); // 每秒检查一次
}

// FileSystemWatcher 方式(高效)
FileSystemWatcher watcher = new FileSystemWatcher
{
    Path = ".",
    Filter = "target.txt"
};
watcher.Created += (s, e) => Console.WriteLine("文件已创建!");
watcher.EnableRaisingEvents = true;

关键注释

第二章:FileSystemWatcher的“潜伏”技巧

2.1 技巧一:监听目录而非文件

“监听目录,而非单个文件” 是减少资源消耗的关键策略。

代码示例:监听整个目录

FileSystemWatcher watcher = new FileSystemWatcher
{
    Path = @"C:\Logs", // 监听整个日志目录
    Filter = "*.log", // 仅监控 .log 文件
    IncludeSubdirectories = true // 包含子目录
};

// 无需为每个文件单独创建监听器
watcher.Created += (s, e) =>
{
    Console.WriteLine($"新日志文件创建: {e.Name}");
};

关键注释

2.2 技巧二:事件聚合与防抖

“防抖” 可避免高频事件(如连续写入)导致的性能问题。

代码示例:防抖处理

private static Timer _debounceTimer;

private static void OnChanged(object source, FileSystemEventArgs e)
{
    Console.WriteLine($"事件触发: {e.Name}"); // 打印原始事件

    // 取消之前的计时器
    _debounceTimer?.Change(Timeout.Infinite, Timeout.Infinite);

    // 设置新的计时器
    _debounceTimer = new Timer(state =>
    {
        Console.WriteLine($"【最终处理】文件: {e.Name}"); // 实际处理逻辑
    }, null, 1000, Timeout.Infinite); // 1秒后执行
}

关键注释

2.3 技巧三:跨平台兼容性优化

“在 Linux/macOS 中也能潜伏?” .NET Core 3.0+ 支持跨平台监听。

代码示例:跨平台监听

FileSystemWatcher watcher = new FileSystemWatcher
{
    Path = "/var/logs", // Linux/macOS 路径
    Filter = "*.log"
};

// 事件处理与 Windows 一致
watcher.Created += (s, e) => Console.WriteLine($"文件创建: {e.Name}");
watcher.EnableRaisingEvents = true;

关键注释

跨平台差异:Linux/macOS 使用 inotify(Linux)或 kqueue(macOS)实现监听。

注意事项

第三章:实战案例——构建“潜伏”型监控系统

3.1 案例一:日志文件实时分析

需求:监控日志目录,实时解析新增日志并触发告警。

代码示例:日志监控器

FileSystemWatcher watcher = new FileSystemWatcher
{
    Path = @"C:\Logs",
    Filter = "*.log",
    IncludeSubdirectories = true
};

watcher.Created += (s, e) =>
{
    Console.WriteLine($"新日志文件: {e.Name}");
    ParseLog(e.FullPath);
};

watcher.Changed += (s, e) =>
{
    Console.WriteLine($"日志更新: {e.Name}");
    ParseLog(e.FullPath);
};

watcher.EnableRaisingEvents = true;

private static void ParseLog(string filePath)
{
    try
    {
        using (var reader = File.OpenText(filePath))
        {
            string line;
            while ((line = reader.ReadLine()) != null)
            {
                if (line.Contains("ERROR"))
                {
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.WriteLine($"【告警】发现错误: {line}");
                    Console.ResetColor();
                }
            }
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine($"解析日志失败: {ex.Message}");
    }
}

关键注释

3.2 案例二:文件同步工具

需求:监控本地目录,将新增文件同步到远程服务器。

代码示例:文件同步器

FileSystemWatcher watcher = new FileSystemWatcher
{
    Path = @"C:\LocalDir",
    Filter = "*.*"
};

watcher.Created += (s, e) =>
{
    Console.WriteLine($"文件创建: {e.Name}");
    UploadFile(e.FullPath);
};

watcher.EnableRaisingEvents = true;

private static void UploadFile(string filePath)
{
    try
    {
        using (var client = new WebClient())
        {
            string remotePath = $"https://remote-server/upload/{Path.GetFileName(filePath)}";
            client.UploadFile(remotePath, filePath);
            Console.WriteLine($"文件已上传: {filePath}");
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine($"上传失败: {ex.Message}");
    }
}

关键注释

第四章:进阶优化——“潜伏”到极致

4.1 优化一:批量事件处理

“一次触发,多次事件” 是常见问题(如重命名操作会触发DeletedCreated事件)。

代码示例:批量事件处理

private static List<FileSystemEventArgs> _eventQueue = new List<FileSystemEventArgs>();
private static Timer _batchTimer;

watcher.Created += (s, e) => _eventQueue.Add(e);
watcher.Deleted += (s, e) => _eventQueue.Add(e);
watcher.Renamed += (s, e) => _eventQueue.Add(e);

// 定期处理事件
_batchTimer = new Timer(state =>
{
    if (_eventQueue.Count > 0)
    {
        Console.WriteLine($"批量处理 { _eventQueue.Count } 个事件");
        foreach (var e in _eventQueue)
        {
            ProcessEvent(e);
        }
        _eventQueue.Clear();
    }
}, null, 0, 5000); // 每5秒处理一次

private static void ProcessEvent(FileSystemEventArgs e)
{
    switch (e.ChangeType)
    {
        case WatcherChangeTypes.Created:
            Console.WriteLine($"创建: {e.Name}");
            break;
        case WatcherChangeTypes.Deleted:
            Console.WriteLine($"删除: {e.Name}");
            break;
        case WatcherChangeTypes.Changed:
            Console.WriteLine($"修改: {e.Name}");
            break;
    }
}

关键注释

4.2 优化二:内存占用控制

“监听器泄漏” 可能导致内存飙升。

代码示例:安全释放监听器

FileSystemWatcher watcher = new FileSystemWatcher
{
    Path = @"C:\Temp",
    Filter = "*.tmp"
};

watcher.Created += (s, e) =>
{
    Console.WriteLine($"文件创建: {e.Name}");
    watcher.Dispose(); // 处理完成后立即释放
};

watcher.EnableRaisingEvents = true;

// 防止主线程退出
Console.ReadLine();

关键注释

第五章:“潜伏”的陷阱与解决方案

5.1 陷阱一:事件丢失

“为何监听不到所有事件?”

解决方案

代码示例

FileSystemWatcher watcher = new FileSystemWatcher
{
    Path = @"C:\HighTrafficDir",
    Filter = "*.*",
    InternalBufferSize = 65536 // 默认8KB,可增加至64KB
};

watcher.Created += (s, e) => Console.WriteLine($"文件创建: {e.Name}");
watcher.EnableRaisingEvents = true;

5.2 陷阱二:跨平台权限问题

“为何在 Linux 上无法监听目录?”

解决方案

调整 inotify 限制

sudo sysctl fs.inotify.max_user_watches=524288

检查目录权限:确保运行程序的用户对目标目录有读写权限。

FileSystemWatcher的“潜伏”之道

技巧类别核心优势适用场景
目录监听减少监听器数量,降低资源消耗日志监控、文件同步
事件防抖避免高频事件导致性能问题日志分析、实时数据处理
跨平台兼容支持 Windows/Linux/macOS跨平台应用、云原生部署
批量处理提升处理效率高频文件操作环境

最终建议

到此这篇关于C#通过FileSystemWatcher监听文件的实战技巧的文章就介绍到这了,更多相关C# FileSystemWatcher监听文件内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文