为什么在Windows中可能会尝试删除一个文件两次工作


Why in Windows might attempting to delete a file twice work?

我一直在努力为我开发的Windows机器编写一个使用PHP的持续集成脚本。

克隆了一个Git存储库后,我无法编写一个脚本来删除它。(.git文件夹和其中的所有内容)。我收到"Permission denied"错误。

似乎断断续续。我试过ping,但失败了,但导致我这个ping票,所以我不是一个人-但使用attrib的解决方案不适合我。

我终于意识到,它只是需要两次尝试删除其中的一些文件夹和/或文件。最后我的PHP代码是这样的:

<?php
function delTree($dir, $ignore = array()) {
    // no need to continue if $dir doesn't exist
    if (!file_exists($dir))
        return true;
    // must not continue if it's a link. trigger an error.
    if (is_link($dir)) {
        trigger_error("Cannot delete $dir: it's a link.", E_ERROR);
        return false;
    }
    // if it's a file, delete it and return.
    if (is_file($dir)) {
        return tryUnlink($dir, 2);
    }
    // it's a directory. so...
    // build an array of files/directories within it to delete
    $files = array_diff(
            scandir($dir), array('.', '..'), $ignore
    );
    // delete each directory within $dir
    foreach ($files as $file) {
        delTree("$dir/$file", $ignore);
    }
    // delete $dir itself
    return tryRmdir($dir, 2);
}
function tryUnlink($file, $attempts = 2){
    $result = unlink($file);
    if (!$result) {
        if ($attempts > 1){
            return tryUnlink($file, $attempts--);
        } else {
            trigger_error("Cannot delete file $file", E_ERROR);
            return false;
        }
    }
    return true;
}
function tryRmdir($dir, $attempts = 2){
    $result = rmdir($dir);
    if (!$result) {
        if ($attempts > 1){
            return tryRmdir($dir, $attempts--);
        } else {
            trigger_error("Cannot delete directory $dir", E_ERROR);
            return false;
        }
    }
    return true;
}

$attempts参数设置为2时调用它们解决了所有问题(12小时后)。

我尝试了chmod这样的事情:将文件转移到0666,关闭IDE,关闭SourceTree,任何打开的资源管理器窗口,戴上锡纸帽,甚至用命令调用exec():

rm -r .git -Force
rmdir .git /s /q

可能还有10个现在就埋在我的仓库里。

原因可能是什么?

函数tryUnlink()tryRmdir()都将导致无限循环(除非它实际上被删除)。请看下面的代码片段+输出。

代码:

<?php
function foo ($attempts = 2) {
   echo "attempts = $attempts'n";
   if ($attempts > 1) {
      foo ($attempts--);
   } else {
      echo "returning with '$attempts <= 1'n";
  }
}
foo(2);
输出:

attempts = 2
attempts = 2
attempts = 2
[...many many many dupes...]
attempts = 2
attempts = 2
attempts = 2
Segmentation fault (core dumped)

考虑到没有说删除在第二次运行时开始。

在Windows 7(或者可能是Vista?)中,第一次尝试删除目录树失败是很少见的,但不是异常的。我认为这是由于文件系统异步处理删除导致的竞争条件。

正如你已经发现的,你可以通过重试操作来解决这个问题;就我个人而言,我从未见过它连续失败两次,尽管为了安全起见,我通常会让它重试三到四次。