监视目录并处理复制的文件-检查复制完成和打开句柄

本文关键字:复制 句柄 检查 文件 处理 监视 | 更新日期: 2023-09-27 18:29:08

我需要查看图像文件(jpeg、png、tif、gif、bmp)的目录,并处理放置在那里的新文件。我正在尝试使用FileSystemWatcher 实现此功能

private void watch()
{
  FileSystemWatcher watcher = new FileSystemWatcher();
  watcher.Path = path;
  watcher.Filter = "*.*";
  watcher.Changed += new FileSystemEventHandler(OnChanged);
  watcher.EnableRaisingEvents = true;
}

但是,在尝试打开文件之前,我如何确保文件已完全复制,并且没有锁定文件的句柄?

监视目录并处理复制的文件-检查复制完成和打开句柄

要在文件完全复制后处理文件,需要添加以下过滤器:

watcher.NotifyFilter = NotifyFilters.LastWrite;

一旦文件完全复制到目录中,就会发出通知

参考:FileSystemWatcher

对于多文件过滤器,您有两个选项:

watcher.Filter = "*.*";

或者使用以下构造函数:

FileSystemWatcher watcher = new FileSystemWatcher("path","*.*");

唯一知道文件是否已完全复制的进程是执行复制的进程。想想看,一个文件只是一个数据流。如果没有额外的信息,就无法知道文件中应该有多少数据。

如果没有某种形式的通信,即文件已被完全复制,任何其他进程唯一能做的就是根据文件未被打开和写入的情况进行猜测,然后希望猜测是正确的。任何类似的依赖于文件不再被写入或被任何其他进程打开的操作都无法处理故障。如果文件由FTP等进程复制,并且由于任何原因,网络连接在复制文件的过程中中断,则"guess-and-hope"进程将错误地将文件标识为完整。

有几种方法可以解决这个问题,但它们都需要发送过程向接收器发送某种类型的信号,表明文件已经完成。

您可以让发送进程发送一个"DONE"文件——在发送DataFile之后,发送进程将发送一个名为DataFile.done的零长度文件。一旦您看到DataFile.done,您就可以肯定地知道DataFile已经被完全复制。如果未看到DataFile.done,则DataFile未完全复制。

如果您的底层操作系统和文件系统支持原子文件重命名操作,您也可以让发送进程重命名文件。您可以让发送过程最初发送DataFile.copying,复制完成后将文件重命名为DataFile。任何扩展名为.copying的文件仍在复制过程中。

某些数据文件格式也表示完整的文件。PDF文件遵循指定的格式,您可以判断它们是否完整。XML文件的构造方式可以让您判断它们是否完整。但这不是一个有效的解决方案,因为它需要解析文件的内容,如果文件很大或有性能要求,则多次连续读取每个文件可能会导致严重的IO性能问题。

同样,如果发送过程不发送某种DONE标志,就无法解决这个问题。接收过程根本没有足够的数据来做任何事情,除了猜测文件何时完成,然后它只能希望做出正确的猜测。

依赖猜测和希望的系统通常不太可靠。