Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/three.js/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何可靠地检查当前正在写入的文件是否已在.net中完成?_C#_.net - Fatal编程技术网

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资源管理器相同

通过Cygwin
cp复制

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

同样的结果

通过Cygwin
cp复制

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

同样的结果

通过Cygwin
cp复制

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)在写入文件时会执行多个操作,每个操作都会报告。可能重复