12

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

4

9 回答 9

5

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

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

于 2008-08-27T13:32:53.573 回答
3

在文件关闭之前,不应触发 FileSystemWatcher 上的“已更改”事件。请参阅我对类似问题的回答。随着新数据的进入,FTP下载机制有可能在下载过程中多次关闭文件,但我认为这不太可能。

于 2008-08-27T13:31:54.213 回答
3

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

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

文件以替代扩展名发送,一旦发件人满意,文件就会被重命名。

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

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

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

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

于 2008-08-27T13:33:15.850 回答
2

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

/// <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);
    }
}

(来自我对相关问题的回答)

于 2009-09-16T08:33:53.320 回答
1

您是否尝试过对文件进行写锁定?如果它正在被写入,那应该会失败,并且你知道让它不理会一点......

于 2008-08-27T13:28:47.933 回答
1

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

于 2008-08-27T13:29:13.503 回答
0

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

于 2008-08-27T13:41:37.593 回答
0

如果文件上传中途失败并且发件人尚未尝试重新发送(和重新锁定)文件,则写锁定将无济于事。

于 2008-08-27T13:58:41.263 回答
0

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

于 2008-08-27T14:02:04.423 回答