c# - 如何判断文件是否已*完全*写入

标签 c# file-io filesystemwatcher

我熟悉 FileSystemWatcher 类,并使用它进行了测试,或者我使用快速循环进行了测试,并在目录中列出了类型文件的目录列表。在这种特殊情况下,它们是 zip 压缩的 SDF 文件,我需要解压、打开和查询。

问题是,当一个大文件放在一个目录中时,有时这需要时间,例如下载它,或从网络位置复制等......

当 FileSystemWatcher 引发 OnChange 事件时,我有一个 ChangeType 的句柄,并且在这些类型的操作中立即创建,而文件仍未完全复制到该位置。

同样使用循环,在整个文件存在之前,我看到一个文件存在。

FileSystemWatcher 引发了几个更改事件,一个是在创建之后,然后是一个或多个在复制过程中,没有任何内容表明This file is now complete

因此,如果我希望将某种类型的文件放置在最终要读取和处理的目录中,而不知道它们的传输机制,也不知道它们的最终大小...

除了使用错误控制作为工作流程控制(尽管错误控制无论如何都应该存在)之外,我如何知道文件何时准备好进行实际处理?这似乎是一种糟糕的处理方式,因为有时错误控制可能实际上代表了一个合法问题,有时可能只是文件没有完全写入,我没有看到任何真正安全的区分方式.

我鄙视预期的错误,但意识到它有它像套接字一样的地方,没有什么能保证在尝试读/写之前检查打开不会改变。但我确实不惜一切代价避免它。

这个特别的问题让我很困扰,主要是因为将要产生的信息含糊不清。有一个文件的冲突队列,这些文件合法地出错,因为它们没有完全遇到或以其他方式损坏,我不希望其他好的文件去那里。几乎不可能更精细地检测这种特定情况。

编辑: 我知道我可以做到这一点...而且我已经阅读了有关其他人做同样事情的其他 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;
            }
        }
    }
}

我想知道的是,这绝对是唯一的方法,是否没有其他组件或文件系统的某些 Hook 可以通过适当的事件实际执行此操作?

最佳答案

唯一的判断方法是使用 FileShare.Read 打开文件。如果进程仍在写入文件并且尚未关闭它,那将始终失败。否则没有任何机制可以知道哪个特定进程正在执行写入,FSW 在文件系统设备驱动程序级别运行,并且不知道任何进程正在执行该操作。可能不止一个。

这在您第一次尝试时经常会失败,FSW 非常有效。一般来说,您不知道该过程将花费多少时间,这当然取决于它的编写方式,并且可能会使文件打开一段时间。可能是几小时或几天,日志文件就是一个例子。

所以你需要一个重试机制,它应该有一个指数退避算法来增加尝试之间的重试延迟。以半秒延迟开始,并在失败时继续增加延迟。这需要在工作线程中完成,而不是 FSW 回调。使用线程安全队列将文件的路径从 FSW 回调传递到工作线程。一般来说,处理您收到的多个 FSW 通知也是一个很好的策略。

注意启动效果,您当然会在开始运行之前错过任何通知,因此可能有大量文件正在等待工作。并注意 Heisenbugs,无论您对文件做什么,都可能导致另一个进程失败。就像这个过程对你的过程所做的一样:)

考虑使用任务计划程序定期运行的批处理程序可能是一个更简单的选择。

关于c# - 如何判断文件是否已*完全*写入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29283155/

相关文章:

c# - 禁用外键约束代码优先 EF

c - 从二进制文件 C 中写入和读取结构

c# - 在 C# 中对单个文件使用 FileSystemWatcher

c# - 使用 FileSystemWatcher 观察 log4net 日志文件

c# - FileSystemWatcher 对硬盘有什么影响?

c# - 如何让 WPF 窗口根据内容自动调整大小

c# - 在 MainActivity 中访问 MainPage.xaml 按钮

c# - 在字典中拆分字符串

java - 如何将逗号分隔的 ArrayList 添加到树中

c - 如何使用 glib 逐行读取 unicode 文件