问题 监控文件 - 如何知道文件何时完成


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


13034
2017-08-27 13:23


起源



答案:


您是否尝试过对文件进行写锁定?如果它被写入,那应该会失败,而且你知道将它留下一点......


1
2017-08-27 13:28



如果文件夹对于监控过程是只读的怎么办? - Eugene Mayevski 'Allied Bits


答案:


您是否尝试过对文件进行写锁定?如果它被写入,那应该会失败,而且你知道将它留下一点......


1
2017-08-27 13:28



如果文件夹对于监控过程是只读的怎么办? - Eugene Mayevski 'Allied Bits


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

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


5
2017-08-27 13:32





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


3
2017-08-27 13:31





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

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

文件与其他扩展程序一起发送,并在发件人满意后重命名。

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

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

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

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


3
2017-08-27 13:33





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

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

(从我的回答到 相关问题


2
2017-09-16 08:33





你可能不得不使用一些带外信号:让“file.ext”的制作人写一个虚拟的“file.ext.end”。


1
2017-08-27 13:29





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


0
2017-08-27 13:41