.NET在复制操作后拒绝访问目录

时间:2010-12-01 12:51:52

标签: c# .net .net-4.0

我正在另一个目录上执行目录的“安全”副本,如下所示:

给定源C:\ Source和目标C:\ Target

  • 将C:\ Source复制到C:\ Target-incoming
  • 将C:\ Target(如果存在)移动到C:\ Target-outgoing
  • 将C:\ Target-incoming移动到C:\ Target
  • 删除C:\ Target-outgoing(如果存在)

如果前三个步骤中的任何一个失败,我会尝试将其恢复原状,以防止数据丢失。

然而,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方法在释放相应文件的锁之前返回,导致在继续之前需要等待一段时间。

4 个答案:

答案 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复制或移动之前检查源目录和目标目录是否存在

访问被拒绝错误是由源或目标引起的。