CodeGo.net>如何知道一个文件是“完全”写
作者:互联网
我熟悉FileSystemWatcher类,并已使用此类进行了测试,或者,我使用快速循环进行了测试,并在目录中列出了类型文件的目录.在这种特殊情况下,它们是zip压缩的SDF文件,我需要解压缩,打开和查询.
问题在于,将大文件放在目录中时,有时会花费一些时间,例如正在下载文件或从网络位置复制文件等.
当FileSystemWatcher引发OnChange事件时,我具有ChangeType的句柄,并且在这些类型的操作上,Create是立即执行的,而文件仍未完全复制到该位置.
同样,使用循环,我看到一个文件在整个文件在那里之前.
FileSystemWatcher引发几个更改事件,一个在创建后发生,然后在复制过程中发生一个或多个,没有什么表示此文件现在已完成
因此,如果我希望将某种类型的文件放置在最终可以读取和处理的目录中,而无需了解它们的传输机制,也不知道它们的最终大小…
我如何知道何时准备好实际处理文件,而不是使用错误控制作为工作流控件(尽管错误控制仍然存在,所以应该存在)?这似乎是处理此问题的一种坏方法,因为有时错误控制实际上可能代表合法问题,有时可能只是文件未完全写入,而且我看不到任何真正安全的区分方法.
我鄙视预期的错误,但是意识到它像套接字一样具有它的位置,没有任何东西可以保证在尝试读/写之前对打开的检查不会改变.但是我不惜一切代价避免这样做.
这个特定的人困扰我,主要是因为将要产生的信息含糊不清.对于文件错误,因为它们没有完全碰到或以其他方式损坏,因此存在一个冲突队列,我不希望其他好的文件进入那里.更加细致地检测这种特定情况几乎是不可能的.
编辑:
我知道我可以做到这一点…而且我已经阅读了SA的其他文章,这些文章涉及其他人在做同样的事情. (我知道这种方法既粗糙又阻塞,这只是一个例子.)
private static void OnChanged(object source, FileSystemEventArgs e)
{
if (e.ChangeType == WatcherChangeTypes.Created)
{
bool ready = false;
while (!ready)
{
try
{
using (FileStream fs = new FileStream(e.FullPath, FileMode.Open))
{
Console.WriteLine(String.Format("{0} - {1}", e.FullPath, fs.Length));
}
ready = true;
}
catch (IOException)
{
ready = false;
}
}
}
}
我试图确定的是,这绝对是唯一的方法,是否没有其他组件,或者是否有某个文件系统的钩子可以通过适当的事件实际完成此操作?
解决方法:
告诉的唯一方法是使用FileShare.Read打开文件.如果进程仍在写入文件并且尚未关闭文件,那将总是失败.否则,没有任何机制可以完全了解哪个进程正在执行写操作,FSW在文件系统设备驱动程序级别上运行,而对哪个进程正在执行该操作一无所知.可能不止一个.
第一次尝试时,这通常会失败,FSW非常有效.通常,您不知道该过程将花费多少时间,它当然取决于编写方式,并且可能会使文件打开一段时间.可能是几小时或几天,一个日志文件就是一个例子.
因此,您需要一个重试机制,它应该具有指数补偿算法,以增加两次尝试之间的重试延迟.以半秒的延迟开始,并在失败时继续增加该延迟.这需要在工作线程中完成,而不是FSW回调.使用线程安全队列将文件的路径从FSW回调传递到工作线程.通常,处理收到的多个FSW通知也是一个不错的策略.
注意启动效果,您当然会在开始运行之前错过任何通知,因此可能有大量文件在等待工作.并注意Heisenbug,无论您对文件进行任何操作都可能导致另一个进程崩溃.这个过程对您的过程很像:)
考虑到使用任务计划程序定期运行的批处理风格的程序可能会更容易.
标签:filesystemwatcher,file-io,c 来源: https://codeday.me/bug/20191120/2044903.html