C# 如何可靠地检查当前正在写入的文件是否已在.net中完成?
我在这方面搜索了很多,发现了很多关于这个主题的其他问题,这些问题归结为使用C# 如何可靠地检查当前正在写入的文件是否已在.net中完成?,c#,.net,C#,.net,我在这方面搜索了很多,发现了很多关于这个主题的其他问题,这些问题归结为使用FileSystemWatcher,在其Changed事件中,使用FileShare.None打开文件进行阅读,并检查是否引发异常。然而,这对我来说只有一半的时间有效 我创建了一个简单的控制台应用程序来测试这种行为,基本上可以归结为以下几点: FileSystemWatcher fsw = new FileSystemWatcher("d:\\locktest"); fsw.Changed += (sender, e) =
FileSystemWatcher
,在其Changed
事件中,使用FileShare.None
打开文件进行阅读,并检查是否引发异常。然而,这对我来说只有一半的时间有效
我创建了一个简单的控制台应用程序来测试这种行为,基本上可以归结为以下几点:
FileSystemWatcher fsw = new FileSystemWatcher("d:\\locktest");
fsw.Changed += (sender, e) => {
String fp = e.FullPath;
Console.WriteLine(fp + " changed");
try {
using(FileStream s = new FileStream(fp, FileMode.Open, FileAccess.Read, FileShare.None)) { }
Console.WriteLine(fp + " complete");
} catch (IOException ex) {
Console.WriteLine(fp + " not complete");
}
};
fsw.Created += (sender, e) => Console.WriteLine(e.FullPath + " created");
fsw.EnableRaisingEvents = true;
Console.ReadKey(); // would immediately exit otherwise
我现在用不同的文件和目录对此进行了测试,以下是我的结果:
小文件(1MiB)
通过Windows资源管理器复制
d:\locktest\1mb created
d:\locktest\1mb changed
d:\locktest\1mb complete
d:\locktest\1mb changed
d:\locktest\1mb complete
d:\locktest\1g created
d:\locktest\1g changed
d:\locktest\1g not complete
d:\locktest\1g changed
d:\locktest\1g complete
d:\locktest\10g created
d:\locktest\10g changed
d:\locktest\10g not complete
d:\locktest\10g changed
d:\locktest\10g not complete
结果:正确,但有两次
通过DOS复制copy
与通过Windows资源管理器相同
通过Cygwincp复制
d:\locktest\1mb created
d:\locktest\1mb changed
d:\locktest\1mb complete
d:\locktest\1g created
d:\locktest\1g changed
d:\locktest\1g complete
d:\locktest\10g created
d:\locktest\10g changed
d:\locktest\10g complete
正确的结果
1GB大文件
通过Windows资源管理器复制
d:\locktest\1mb created
d:\locktest\1mb changed
d:\locktest\1mb complete
d:\locktest\1mb changed
d:\locktest\1mb complete
d:\locktest\1g created
d:\locktest\1g changed
d:\locktest\1g not complete
d:\locktest\1g changed
d:\locktest\1g complete
d:\locktest\10g created
d:\locktest\10g changed
d:\locktest\10g not complete
d:\locktest\10g changed
d:\locktest\10g not complete
正确的结果
通过DOS复制copy
同样的结果
通过Cygwincp复制
d:\locktest\1mb created
d:\locktest\1mb changed
d:\locktest\1mb complete
d:\locktest\1g created
d:\locktest\1g changed
d:\locktest\1g complete
d:\locktest\10g created
d:\locktest\10g changed
d:\locktest\10g complete
这也是一个正确的结果
大文件(10Gb)
通过Windows资源管理器复制
d:\locktest\1mb created
d:\locktest\1mb changed
d:\locktest\1mb complete
d:\locktest\1mb changed
d:\locktest\1mb complete
d:\locktest\1g created
d:\locktest\1g changed
d:\locktest\1g not complete
d:\locktest\1g changed
d:\locktest\1g complete
d:\locktest\10g created
d:\locktest\10g changed
d:\locktest\10g not complete
d:\locktest\10g changed
d:\locktest\10g not complete
最后一个“更改”事件是“太早”触发的,或者更好:文件完成时不会触发“更改”事件
通过DOS复制copy
同样的结果
通过Cygwincp复制
d:\locktest\1mb created
d:\locktest\1mb changed
d:\locktest\1mb complete
d:\locktest\1g created
d:\locktest\1g changed
d:\locktest\1g complete
d:\locktest\10g created
d:\locktest\10g changed
d:\locktest\10g complete
正确的结果
那么,如果写入监视目录的文件确实是“完整的”,即“可用的”,我应该如何进行可靠的检测呢
我目前的做法如下:
FileSystemWatcher fsw = new FileSystemWatcher("d:\\locktest");
fsw.Changed += (sender, e) => {
String fp = e.FullPath;
Console.WriteLine(fp + " changed");
try {
using(FileStream s = new FileStream(fp, FileMode.Open, FileAccess.Read, FileShare.None)) { }
Console.WriteLine(fp + " complete");
} catch (IOException ex) {
Console.WriteLine(fp + " not complete");
}
};
fsw.Created += (sender, e) => Console.WriteLine(e.FullPath + " created");
fsw.EnableRaisingEvents = true;
Console.ReadKey(); // would immediately exit otherwise
收听创建的和完成的
尝试在那里打开文件
如果打开文件失败,请将此文件作为“候选文件”放入要再次检查的文件(同步)列表中
每X秒检查一次此列表
如果列表中的一个文件发生了更改
,请将其从列表中删除并立即检查,再次失败时重新添加
这涉及到某种轮询,在我看来有点“黑客化”。另外,对于非常小的文件,我会两次获得完整的信息,因此我想我必须跟踪已经完成的文件,并检查它们是否已经更改
这是唯一的方法还是有更好的方法?所有文件都是由您自己的代码创建的吗?难道您不能循环直到文件打开吗?这似乎太过分了。不,它们是由运行在其他计算机上的第三方应用程序创建的。它们将文件写入我的应用程序运行的计算机上的驱动器,然后该驱动器被导出到其他计算机上o将它们作为Windows共享。遗憾的是,您无法保证FSW文件操作会发生一系列不同的事件,因为某些应用程序(如示例中的shell)在写入文件时会执行多个操作,每个操作都会报告。可能重复