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

如何测试文件是否在.NET中完全复制,.net,file,copy,.net,File,Copy,我正在监视文件夹中的新文件,需要对其进行处理。问题是,有时文件打开失败,因为系统尚未完成复制 测试文件是否已完成复制的正确方法是什么 澄清: 我没有对文件夹/文件的写入权限,也无法控制复制过程(由用户负责)。我通常采用的一种方法是在复制/传输结束时创建一个名为“token.txt”的文件,但不包含任何内容。其思想是,此文件将在传输操作结束时创建,因此您可以监视此文件的创建,并在创建此文件时开始处理您的文件。当您开始处理文件时,不要忘记始终擦除此令牌文件。您还应涵盖以下情况:文件被其他程序使用、文

我正在监视文件夹中的新文件,需要对其进行处理。问题是,有时文件打开失败,因为系统尚未完成复制

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

澄清:
我没有对文件夹/文件的写入权限,也无法控制复制过程(由用户负责)。

我通常采用的一种方法是在复制/传输结束时创建一个名为“token.txt”的文件,但不包含任何内容。其思想是,此文件将在传输操作结束时创建,因此您可以监视此文件的创建,并在创建此文件时开始处理您的文件。当您开始处理文件时,不要忘记始终擦除此令牌文件。

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


使用扩展的异常处理来覆盖可能发生的所有重要情况。

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

如果您正在使用,我认为没有可靠的解决方案。一种方法是稍后重试/捕获/重试。

如果您无法控制复制过程,则重试循环可能是最好的方法

如果您有控制权:

  • 如果文件夹是本地的,您可以要求向其中写入内容的人锁定文件以进行独占访问,并且只有在完成后才释放锁定(我认为这是file.Copy的默认设置)。在.Net端,您可以有一个简单的重试循环,并有一个冷却期。
    • 或者,您可以将文件写入临时文件夹,并仅在写入后将其移动到目标目录。这减少了坏东西可能发生的窗口(但并没有消除它)
  • 如果该文件夹是SMB共享,则有可能甚至不起作用(某些linux实现)。在这种情况下,常用的方法是有一种锁文件,一旦创建文件的人完成了,该文件就会被删除。锁定文件方法的问题是,如果忘记删除它,可能会有麻烦
  • 考虑到这些复杂情况,我建议通过WCF服务或web服务接收数据可能是有利的,因为您有更好的控制能力
我认为唯一可靠的方法是尝试以独占方式打开文件并捕获特定异常。我通常不喜欢在正常的应用程序逻辑中使用异常,但我担心在这种情况下没有其他方法(至少我还没有找到):


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

如果您执行以下操作:

while (file is locked)
    no-op()
process file()
您可能会有另一个进程在while-guard和process-file语句之间跳转的风险。无论“等待文件可用性”是如何实现的,除非您能够确保post unlock是第一个访问它的进程,否则您可能不是第一个用户

乍一看,这种情况更可能发生,特别是当有多人在观看文件时,尤其是当他们使用类似文件系统监视程序的东西时。当然,即使到那时也不太可能…

文件大吗

也许您可以尝试计算文件上的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"));

下面是我使用的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

好问题!当我遇到这个问题时,我只是添加了System.Threading.Thread.Sleep(1000),但我很想得到一个更好的解决方案(它太差劲了…),你有原始文件的读取权限吗,正在复制哪个?但如果用户帐户无权删除服务器中的文件,则此方法将毫无用处。不要认为extropy正在等待由他自己控制的复制过程。那么就不会有令牌文件了,对吧?我想你不能说如果没有一个没有更多细节的过程,他是否有访问/控制权。这就像是一场头脑风暴,每个人都提供意见。
 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