如何通过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
相关产品推荐
相关产品推荐

