监视文件-如何知道文件何时完成

时间:2020-03-05 18:43:50  来源:igfitidea点击:

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

解决方案

回答

我们是否尝试过对该文件进行写锁定?如果正在写入,那应该会失败,并且我们知道将其搁置一会儿...

回答

我们可能必须进行一些带外信令:让" file.ext"的生产者编写一个虚拟的" file.ext.end"。

回答

在关闭文件之前,不应触发FileSystemWatcher上的" Changed"事件。看到我对类似问题的回答。随着新数据的传入,FTP下载机制可能会在下载过程中多次关闭文件,但我认为这种可能性很小。

回答

如果我们控制着将文件写入目录的程序,则可以让程序将文件写入临时目录,然后将其移至监视目录。该移动应该是原子操作,因此观察者应该在文件完全位于目录中之前才能看到该文件。

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

回答

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

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

文件以备用扩展名发送,一旦发件人满意,文件将被重命名。

显然,以上内容与定期清除带有临时扩展名的旧文件的过程结合在一起。

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

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

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

回答

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

回答

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

回答

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

回答

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

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

(根据我对相关问题的回答)