我们有几个.NET应用程序使用FileSystemWatcher监视新文件的目录。文件从其他位置复制,通过FTP上传等。当它们进入时,文件将以这种或那种方式处理。但是,我从未见过一个令人满意的答案的一个问题是:对于大文件,如何知道被监视的文件何时仍被写入?显然,我们需要等到文件完成并关闭才开始处理它们。 FileSystemWatcher事件中的事件args似乎没有解决这个问题。
答案 0 :(得分:5)
如果您可以控制将文件写入目录的程序,则可以让程序将文件写入临时目录,然后将其移动到监视目录中。移动应该是一个原子操作,因此观察者在完全进入目录之前不应该看到该文件。
如果您无法控制对已观看目录的写入内容,则可以在观察者中设置一个时间,当该文件在给定时间内保持相同大小时,该时间将被视为已完成。如果不关心立即处理,将此计时器设置为相对较大的是一种相当安全的方法,可以知道文件是完整的还是永远不会的。
答案 1 :(得分:3)
FileSystemWatcher上的“Changed”事件不应该在文件关闭之前触发。查看我的answer to a similar question。随着新数据的进入,FTP下载机制有可能在下载过程中多次关闭文件,但我认为这有点不太可能。
答案 2 :(得分:3)
除非文件的内容可以验证完成(它具有可验证的格式或包含内容的校验和),否则只有发件人才能验证整个文件是否已到达。
我过去曾使用锁定方法通过FTP发送大文件。
文件与其他扩展程序一起发送,并在发件人满意之后重命名。
上述内容显然与一个定期整理旧文件的过程相结合。
另一种方法是创建一个具有相同名称但附加.lck扩展名的零长度文件。完全上载真实文件后,将删除lck文件。接收过程显然会忽略具有锁定文件名称的文件。
如果没有这样的系统,接收者永远无法确定整个文件是否已到达。
检查x分钟内未更改的文件容易出现各种问题。
答案 3 :(得分: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);
}
}
(从我对related question的答案)
答案 4 :(得分:1)
您是否尝试过对文件进行写锁定?如果它被写入,那应该会失败,并且你知道不管它一点......
答案 5 :(得分:1)
你可能必须使用一些带外信号:让“file.ext”的制作人写一个虚拟的“file.ext.end”。
答案 6 :(得分:0)
+1,其中file.ext.end的内容是较大文件的校验和。这不是为了安全,而是为了确保在此过程中没有任何乱码。如果有人可以将自己的文件插入到大流中,他们也可以替换校验和。
答案 7 :(得分:0)
如果文件上传失败并且发件人尚未尝试重新发送(和重新锁定)文件,则写入锁无效。
答案 8 :(得分:0)
我在Windows中检查文件是否已被ftp完全上传的方法是尝试重命名。如果重命名失败,则文件不完整。我承认,不是很优雅,但它确实有效。