You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过C# WinForms的FileSystemWatcher判断大文件复制完成?

判断文件复制完成的可行方案

针对你用FileSystemWatcher监控c:\Backup文件夹时遇到的大文件复制完成判断问题,这里给几个实用的实现思路:

1. 文件独占锁检测法

文件正在复制时,系统会对文件加独占锁,复制完成后锁会释放。你可以尝试以独占模式打开文件,能成功打开就说明文件已就绪。为了避免因网络延迟、系统缓存导致的误判,建议加上重试机制。

示例代码:

private bool IsFileReady(string filePath)
{
    try
    {
        using (var stream = File.Open(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
        {
            return stream != null;
        }
    }
    catch (IOException)
    {
        // 文件被占用,还在复制中
        return false;
    }
}

// 在Changed事件中调用
private void Watcher_Changed(object sender, FileSystemEventArgs e)
{
    if (e.ChangeType == WatcherChangeTypes.Changed)
    {
        // 重试3次,每次间隔500毫秒
        int retryCount = 0;
        while (retryCount < 3)
        {
            if (IsFileReady(e.FullPath))
            {
                // 执行压缩和发送操作
                ProcessFileOrFolder(e.FullPath);
                break;
            }
            retryCount++;
            Thread.Sleep(500);
        }
    }
}

2. 文件大小稳定检测法

记录文件的初始大小,间隔一段时间后再次获取大小,如果两次大小一致,说明文件复制完成。这种方法适合大文件传输场景,能有效避免锁检测的偶尔误判。

示例代码:

private Dictionary<string, long> _fileSizeTracker = new Dictionary<string, long>();

private void Watcher_Changed(object sender, FileSystemEventArgs e)
{
    if (e.ChangeType == WatcherChangeTypes.Changed && File.Exists(e.FullPath))
    {
        FileInfo fileInfo = new FileInfo(e.FullPath);
        long currentSize = fileInfo.Length;

        if (_fileSizeTracker.TryGetValue(e.FullPath, out long lastSize))
        {
            if (currentSize == lastSize)
            {
                // 大小稳定,说明复制完成
                ProcessFileOrFolder(e.FullPath);
                _fileSizeTracker.Remove(e.FullPath);
            }
        }
        else
        {
            _fileSizeTracker[e.FullPath] = currentSize;
            // 1秒后再次检查
            Task.Delay(1000).ContinueWith(t =>
            {
                if (_fileSizeTracker.ContainsKey(e.FullPath))
                {
                    // 再次触发检查
                    Watcher_Changed(sender, e);
                }
            });
        }
    }
}

3. 结合Changed事件触发次数

根据你观察到的“复制时触发两次Changed事件”的规律,可以给每个文件维护一个触发计数,当第二次触发Changed时,再通过锁检测或大小验证确认文件是否就绪,避免直接基于次数判断的误判。

示例代码:

private Dictionary<string, int> _changedEventCounter = new Dictionary<string, int>();

private void Watcher_Changed(object sender, FileSystemEventArgs e)
{
    if (e.ChangeType == WatcherChangeTypes.Changed)
    {
        if (_changedEventCounter.TryGetValue(e.FullPath, out int count))
        {
            count++;
            if (count >= 2)
            {
                if (IsFileReady(e.FullPath))
                {
                    ProcessFileOrFolder(e.FullPath);
                    _changedEventCounter.Remove(e.FullPath);
                }
            }
            _changedEventCounter[e.FullPath] = count;
        }
        else
        {
            _changedEventCounter[e.FullPath] = 1;
        }
    }
}

针对文件夹的处理

文件夹的Created事件触发时,文件夹本身已经创建完成,但内部的文件可能还在传输。你可以在文件夹Created事件中,给文件夹内的文件单独添加监控逻辑,或者等待一段时间后遍历文件夹内的文件,逐一验证是否就绪。

内容的提问来源于stack exchange,提问作者Mohsen K

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 15:13:00