我们有几个 .NET 应用程序使用 FileSystemWatcher 监视目录中的新文件。文件是从其他位置复制、通过 FTP 上传等。当它们进来时,文件会以一种或另一种方式进行处理。然而,我从未见过令人满意的答案的一个问题是:对于大文件,如何知道正在监视的文件何时仍在写入?显然,我们需要等到文件完成并关闭后再开始处理它们。FileSystemWatcher 事件中的事件参数似乎没有解决这个问题。

有帮助吗?

解决方案

您是否尝试过对文件进行写锁定?如果它被写入,那应该会失败,并且你知道暂时不要管它......

其他提示

如果您可以控制将文件写入目录的程序,则可以让程序将文件写入临时目录,然后将它们移动到监视目录中。移动应该是一个原子操作,因此观察者在文件完全进入目录之前不应看到该文件。

如果您无法控制写入监视目录的内容,则可以在监视程序中设置一个时间,当文件在给定时间内保持相同大小时,文件将被视为完整。如果不关心立即处理,则将此计时器设置为相对较大的值是一种相当安全的方法,可以知道文件是否完整或永远不会完整。

在文件关闭之前,不应触发 FileSystemWatcher 上的“Changed”事件。看我的 回答类似的问题. 。当新数据进入时,FTP 下载机制有可能在下载过程中多次关闭文件,但我认为这不太可能。

除非可以验证文件的内容是否完整(它具有可验证的格式或包括内容的校验和),否则只有发送者可以验证整个文件是否已到达。

我过去曾使用锁定方法通过 FTP 发送大文件。

文件以备用扩展名发送,并在发件人满意后重命名。

上述显然与定期清理具有临时扩展名的旧文件的过程相结合。

另一种方法是创建一个同名但带有附加 .lck 扩展名的零长度文件。一旦真实文件完全上传,lck 文件就会被删除。接收进程显然会忽略具有锁定文件名称的文件。

如果没有这样的系统,接收者永远无法确定整个文件是否已到达。

检查 x 分钟内未更改的文件很容易出现各种问题。

以下方法尝试打开具有写权限的文件。它将阻止执行,直到文件完全写入磁盘:

/// <summary>
/// Waits until a file can be opened with write permission
/// </summary>
public static void WaitReady(string fileName)
{
    while (true)
    {
        try
        {
            using (System.IO.Stream stream = System.IO.File.Open(fileName, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
            {
                if (stream != null)
                {
                    System.Diagnostics.Trace.WriteLine(string.Format("Output file {0} ready.", fileName));
                    break;
                }
            }
        }
        catch (FileNotFoundException ex)
        {
            System.Diagnostics.Trace.WriteLine(string.Format("Output file {0} not yet ready ({1})", fileName, ex.Message));
        }
        catch (IOException ex)
        {
            System.Diagnostics.Trace.WriteLine(string.Format("Output file {0} not yet ready ({1})", fileName, ex.Message));
        }
        catch (UnauthorizedAccessException ex)
        {
            System.Diagnostics.Trace.WriteLine(string.Format("Output file {0} not yet ready ({1})", fileName, ex.Message));
        }
        Thread.Sleep(500);
    }
}

(从我的回答 相关问题)

您可能必须使用一些带外信号:让“file.ext”的生产者编写一个虚拟的“file.ext.end”。

如果可能的话,使用 file.ext.end 信号器+1,其中 file.ext.end 的内容是较大文件的校验和。这与其说是为了安全,不如说是为了确保一路上不会出现任何乱码。如果有人可以将自己的文件插入大流中,他们也可以替换校验和。

如果文件上传中途失败并且发件人尚未尝试重新发送(并重新锁定)文件,则写锁定不起作用。

我在 Windows 中检查文件是否已通过 ftp 完全上传的方法是尝试重命名它。如果重命名失败,则文件不完整。我承认不是很优雅,但它确实有效。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top