在 C# 中,如果你想 监控文件的创建,并确保文件完全写入完成后再处理,单纯用 FileSystemWatcher
监听 Created
事件是不够的,因为 Created
触发时文件可能还在写入中,直接打开可能报错或读取不完整。
下面我给你一个完整的思路和示例:
1️⃣ 使用 FileSystemWatcher 监听文件创建
using System;
using System.IO;
class Program
{
static void Main()
{
string folderPath = @"C:\Temp";
FileSystemWatcher watcher = new FileSystemWatcher(folderPath);
watcher.Filter = "*.txt"; // 监控特定文件类型
watcher.Created += OnCreated;
watcher.EnableRaisingEvents = true;
Console.WriteLine("监控开始,按回车退出...");
Console.ReadLine();
}
private static void OnCreated(object sender, FileSystemEventArgs e)
{
Console.WriteLine($"检测到文件创建: {e.FullPath}");
// 延迟处理
ProcessFileWhenReady(e.FullPath);
}
}
2️⃣ 检查文件是否可用
因为 Created
事件触发时文件可能仍被写入,我们可以尝试打开文件直到成功:
private static void ProcessFileWhenReady(string filePath)
{
const int maxRetries = 10;
const int delayMs = 500;
for (int i = 0; i < maxRetries; i++)
{
try
{
// 尝试以只读方式打开文件
using (FileStream stream = File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.None))
{
Console.WriteLine($"文件准备就绪: {filePath}");
// 在这里处理文件
string content = File.ReadAllText(filePath);
Console.WriteLine($"文件内容长度: {content.Length}");
break; // 成功就退出循环
}
}
catch (IOException)
{
// 文件被占用,等待一段时间再重试
System.Threading.Thread.Sleep(delayMs);
}
}
}
✅ 原理
File.Open(..., FileShare.None)
尝试独占文件。- 如果文件正在写入,会抛出
IOException
。 - 捕获异常后等待一段时间再重试,直到文件写入完成。
3️⃣ 可优化方式
- 异步处理:使用
Task.Run
避免阻塞事件线程。 - 文件大小判断:连续两次文件大小相同再处理,也可以判断文件是否完成写入。
private static async Task ProcessFileWhenReadyAsync(string filePath)
{
long lastSize = -1;
while (true)
{
var info = new FileInfo(filePath);
if (info.Length > 0 && info.Length == lastSize)
break;
lastSize = info.Length;
await Task.Delay(500);
}
// 文件完成写入
string content = await File.ReadAllTextAsync(filePath);
Console.WriteLine($"文件完成写入, 长度: {content.Length}");
}
4️⃣ 总结
FileSystemWatcher
捕获文件创建事件。- 文件可能未写完,直接处理会失败。
- 通过:
- 独占打开文件尝试,或
- 判断文件大小稳定
等方法,确保文件完成写入后再处理。
- 可结合异步方式提高性能和响应速度。
发表回复