我正在另一个目录上执行目录的“安全”副本,如下所示:
给定源C:\ Source和目标C:\ Target
如果前三个步骤中的任何一个失败,我会尝试将其恢复原状,以防止数据丢失。
然而,C:\ Target-incoming移动到C:\ Target失败,大多数时候“访问路径C:\ Target-incoming被拒绝”。
目前,在移动操作之前插入Thread.Sleep(100)可以解决问题。然而,等待.1秒对我来说似乎很荒谬。 Thread.Sleep(10)不足以修复它。我也有下沉的感觉,我必须等待的值取决于磁盘IO的速度。
所以,我的问题:
编辑:为清楚起见,我在一个线程上的一个方法中执行所有这些操作,而我只是使用Thread.Sleep()暂停代码流。移动和副本使用标准.NET Directory.Move(),Directory.CreateDirectory()和File.CopyTo()方法完成。似乎.NET方法在释放相应文件的锁之前返回,导致在继续之前需要等待一段时间。
答案 0 :(得分:1)
可能发生的事情可能是你的线程试图“将C:\ Target-incoming转移到C:\ Target” WHILE “将C:\ Target移动到C:\ Target-传出“没有完成YET。 短线程休眠后,您的过程成功确认此跟踪。 尝试链接你的过程,即:将每一步划分为特定的方法,并一个接一个地调用方法(将方法的开头同步到前一个方法的结尾) 有多种方法可以做到这一点(其中包括同步/锁定/链接每个进程/步骤的不同线程)
您可以在.NET中查看Thread Synchronization
但当然,这不是解决问题的唯一可能原因。
答案 1 :(得分:1)
经过一系列测试后,似乎尝试移动锁定文件夹的行为让操作系统快点并释放锁定,即使第一次尝试失败也是如此。
我将此扩展方法写入DirectoryInfo:
public static void TryToMoveTo(this DirectoryInfo o, string targetPath) {
int attemptsRemaining = 5;
while (true) {
try {
o.MoveTo(targetPath);
break;
} catch (Exception) {
if (attemptsRemaining == 0) {
throw;
} else {
attemptsRemaining--;
System.Threading.Thread.Sleep(10);
}
}
}
}
在调试原始问题时,我决定等待100毫秒,因为任何不太可能导致例外(我尝试了10,25,50,75和100毫秒)。但是,在上面的方法中,我在重试之前等待10ms,而且我从来没有,曾在我的数百次测试运行中抛出了多个异常。
答案 2 :(得分:1)
你总是可以尝试循环,直到最多尝试次数。您可以通过调用CreateFile并检查其返回代码来检查目录是否已锁定。请务必阅读文档的“标志”部分,因为您需要传入一个特殊标志来打开目录。
评论中提及您可能想要尝试使用Transactional NTFS的其他人。如果可以的话,你可能想尝试一下。
答案 3 :(得分:-1)
在使用io.directory.exists复制或移动之前检查源目录和目标目录是否存在
访问被拒绝错误是由源或目标引起的。