如何测试文件是否在.NET中完全复制

时间:2009-07-20 07:34:07

标签: .net file copy

我正在监视新文件的文件夹,需要处理它们。问题是偶尔文件打开失败,因为系统还没有完成复制。

测试文件是否完成复制的正确方法是什么?

澄清: 我没有文件夹/文件的写权限,无法控制复制过程(这是用户)。

9 个答案:

答案 0 :(得分:11)

我认为唯一可靠的方法是尝试独占打开文件并捕获特定的异常。我通常讨厌使用普通应用程序逻辑的异常,但我担心这种情况没有其他方法(至少我还没有找到):

public bool FileIsDone(string path)
{
  try
  {
    using (File.Open(path, FileMode.Open, FileAccess.Read, FileShare.None))
    {
    }
  }
  catch(UnauthorizedAccessException)
  {
    return false;
  }

  return true;
}

答案 1 :(得分:2)

不确定“正确的方法”,但您可以使用监控工具(我猜是FileSystemWatcher)来填充您用于延迟处理的内部队列。或者更好的是:只需使用队列将文件置于打开失败的文件中,以便稍后重试。

答案 2 :(得分:1)

如果您使用的是FileSystemWatcher,我认为这个问题没有一个强大的解决方案。一种方法是稍后尝试/捕获/重试。

答案 3 :(得分:0)

我总是采用的一种方法是在我的副本/传输的末尾创建一个名为“token.txt”而没有内容的文件。我们的想法是,这个文件将在传输操作结束时创建,因此您可以监视此文件的创建,并在创建此文件时开始使用您的文件。当您开始处理文件时,请不要忘记始终删除此令牌文件。

答案 4 :(得分:0)

您还应该涵盖以下情况:文件正被其他程序使用,文件被删除(复制未成功)等。

使用扩展异常处理来涵盖可能发生的所有重要案例。

答案 5 :(得分:0)

这取决于,如果您无法控制复制过程,则重试循环可能是您可以做的最好的。

如果你有控制权:

  • 如果文件夹是本地文件夹,则可能要求人们在其中编写内容以锁定文件以进行独占访问,并且仅在完成时释放锁定(我认为这是File.Copy的默认设置)。在.Net方面,你可以有一个简单的重试循环,有一个冷却期。
    • 或者,您可以将文件写入临时文件夹,并且只有在写入后才能将其移动到目标目录。这会减少可能发生坏事的窗口(但不会消除它)
  • 如果文件夹是SMB共享,​​则LockFile甚至无法工作(某些Linux实现)。在这种情况下,常见的方法是使用一种锁文件,一旦创建文件的人完成就删除该文件。锁定文件方法的问题是,如果您忘记删除它,您可能会遇到麻烦。
  • 在出现这些复杂情况后,我建议通过WCF服务或Web服务接收数据可能是有利的,因为您可以更好地控制。

答案 6 :(得分:0)

事实上,为避免竞争条件,唯一安全的解决方案是重试。

如果您执行以下操作:

while (file is locked)
    no-op()
process file()

你冒着另一个进程在while guard和process file语句之间跳跃的风险。无论您如何实施“等待文件可用性”,除非您确保解锁后是第一个访问它的过程,否则您可能成为第一个用户。

乍一看似乎更有可能,特别是如果有多个人正在观看文件,特别是如果他们正在使用类似文件系统观察者的东西。当然,即便如此,它仍然不太可能......

答案 7 :(得分:0)

文件大吗?

也许您可以尝试计算文件中的md5校验和?

如果您将md5哈希放在文件名中,则可以检索它并尝试重新计算文件的校验和。当md5匹配时,您可以认为该文件已完成。

byte[] md5Hash = null;
MD5 md5 = new MD5CryptoServiceProvider();
using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
   md5Hash = md5.ComputeHash(fs);

StringBuilder hex = new StringBuilder();
foreach (byte b in md5Hash)
    hex.Append(b.ToString("x2"));

答案 8 :(得分:0)

这是我使用的vb.net循环。 每次检查之间等待2秒钟。

 Dim donotcopy As Boolean = True
 While donotcopy = True
     Dim myFile As New FileInfo("Filetocopy")
     Dim sizeInBytes As Long = myFile.Length
     Thread.Sleep(2000)
     Dim myFile2 As New FileInfo("Filetocopy")
     Dim sizeInBytes2 As Long = myFile2.Length
     If sizeInBytes2 = sizeInBytes Then donotcopy = False
 End While