404

我正在使用 .NET 3.5,尝试使用以下方法递归删除目录:

Directory.Delete(myPath, true);

我的理解是,如果文件正在使用或存在权限问题,这应该抛出,否则它应该删除目录及其所有内容。

但是,我偶尔会得到这个:

System.IO.IOException: The directory is not empty.
    at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
    at System.IO.Directory.DeleteHelper(String fullPath, String userPath, Boolean recursive)
    at System.IO.Directory.Delete(String fullPath, String userPath, Boolean recursive)
    ...

我对这个方法有时会抛出并不感到惊讶,但是当递归为真时,我很惊讶得到这个特定的消息。(我知道目录不是空的。)

有没有理由我会看到这个而不是 AccessViolationException?

4

27 回答 27

241

编者注:虽然这个答案包含一些有用的信息,但事实上它是关于Directory.Delete. 请阅读此答案的评论以及此问题的其他答案。


我之前遇到过这个问题。

问题的根源在于此函数不会删除目录结构中的文件。所以你需要做的是创建一个函数,删除目录结构中的所有文件,然后删除所有目录,然后再删除目录本身。我知道这违背了第二个参数,但这是一种更安全的方法。此外,您可能希望在删除文件之前从文件中删除只读访问属性。否则会引发异常。

只需将此代码添加到您的项目中即可。

public static void DeleteDirectory(string target_dir)
{
    string[] files = Directory.GetFiles(target_dir);
    string[] dirs = Directory.GetDirectories(target_dir);

    foreach (string file in files)
    {
        File.SetAttributes(file, FileAttributes.Normal);
        File.Delete(file);
    }

    foreach (string dir in dirs)
    {
        DeleteDirectory(dir);
    }

    Directory.Delete(target_dir, false);
}

另外,对我来说,我个人对允许删除的机器区域添加了限制,因为您是否希望有人在C:\WINDOWS (%WinDir%)或上调用此功能C:\

于 2008-11-30T22:24:23.023 回答
192

如果您尝试递归删除目录a并且目录a\b在资源管理器中打开,b将被删除,但您会收到错误“目录不是空的”,a即使您去查看时它是空的。任何应用程序(包括资源管理器)的当前目录都保留了该目录的句柄。当您调用 时Directory.Delete(true),它会从下往上删除:b,然后a。如果b在资源管理器中打开,资源管理器将检测删除b,向上更改目录cd ..并清理打开的句柄。由于文件系统是异步操作的,所以Directory.Delete操作会因为与资源管理器的冲突而失败。

不完整的解决方案

我最初发布了以下解决方案,其想法是中断当前线程以允许资源管理器有时间释放目录句柄。

// incomplete!
try
{
    Directory.Delete(path, true);
}
catch (IOException)
{
    Thread.Sleep(0);
    Directory.Delete(path, true);
}

但这仅在打开目录是您要删除的目录的直接子目录时才有效。如果a\b\c\d在资源管理器中打开并且您在 上使用它,则此技术在删除和a后将失败。dc

一个更好的解决方案

即使在资源管理器中打开了较低级别的目录之一,此方法也将处理深层目录结构的删除。

/// <summary>
/// Depth-first recursive delete, with handling for descendant 
/// directories open in Windows Explorer.
/// </summary>
public static void DeleteDirectory(string path)
{
    foreach (string directory in Directory.GetDirectories(path))
    {
        DeleteDirectory(directory);
    }

    try
    {
        Directory.Delete(path, true);
    }
    catch (IOException) 
    {
        Directory.Delete(path, true);
    }
    catch (UnauthorizedAccessException)
    {
        Directory.Delete(path, true);
    }
}

尽管我们自己进行了额外的递归工作,但我们仍然必须处理在UnauthorizedAccessException此过程中可能发生的事情。目前尚不清楚第一次删除尝试是否为第二次成功的删除尝试铺平了道路,或者仅仅是抛出/捕获允许文件系统赶上的异常所引入的时间延迟。

您可以通过Thread.Sleep(0)在块的开头添加 a 来减少在典型条件下引发和捕获的异常数量try。此外,在繁重的系统负载下,您可能会经历两次Directory.Delete尝试并失败。将此解决方案视为更强大的递归删除的起点。

一般回答

此解决方案仅解决与 Windows 资源管理器交互的特殊性。如果您想要一个坚如磐石的删除操作,要记住的一件事是,任何东西(病毒扫描程序等)都可以随时对您要删除的内容有一个开放的句柄。所以你必须稍后再试。多久之后,以及尝试多少次,取决于删除对象的重要性。正如MSDN 指出的那样,

健壮的文件迭代代码必须考虑文件系统的许多复杂性。

这个无辜的声明,只提供了一个指向 NTFS 参考文档的链接,应该会让你毛骨悚然。

编辑:很多。这个答案最初只有第一个不完整的解决方案。)

于 2009-11-09T21:01:43.700 回答
45

在继续之前,请检查您可以控制的以下原因:

  • 文件夹是否设置为进程的当前目录?如果是,请先将其更改为其他内容。
  • 您是否从该文件夹中打开了一个文件(或加载了一个 DLL)?(忘记关闭/卸载它)

否则,请检查您无法控制的以下合法原因:

  • 该文件夹中有标记为只读的文件。
  • 您没有删除其中某些文件的权限。
  • 文件或子文件夹在资源管理器或其他应用程序中打开。

如果出现上述任何问题,您应该在尝试改进删除代码之前了解它发生的原因。您的应用应该删除只读文件还是不可访问文件?谁以这种方式标记它们,为什么?

一旦排除了上述原因,仍有可能出现虚假故障。如果有人持有任何要删除的文件或文件夹的句柄,则删除将失败,并且有人可能会枚举文件夹或读取其文件的原因有很多:

  • 搜索索引器
  • 杀毒软件
  • 备份软件

处理虚假失败的一般方法是多次尝试,在尝试之间暂停。你显然不想永远尝试,所以你应该在尝试一定次数后放弃,要么抛出异常,要么忽略错误。像这样:

private static void DeleteRecursivelyWithMagicDust(string destinationDir) {
    const int magicDust = 10;
    for (var gnomes = 1; gnomes <= magicDust; gnomes++) {
        try {
            Directory.Delete(destinationDir, true);
        } catch (DirectoryNotFoundException) {
            return;  // good!
        } catch (IOException) { // System.IO.IOException: The directory is not empty
            System.Diagnostics.Debug.WriteLine("Gnomes prevent deletion of {0}! Applying magic dust, attempt #{1}.", destinationDir, gnomes);

            // see http://stackoverflow.com/questions/329355/cannot-delete-directory-with-directory-deletepath-true for more magic
            Thread.Sleep(50);
            continue;
        }
        return;
    }
    // depending on your use case, consider throwing an exception here
}

在我看来,所有删除都应该使用这样的助手,因为总是可能出现虚假故障。但是,您应该根据您的用例调整此代码,而不是盲目地复制它。

我的应用程序生成的内部数据文件夹出现虚假故障,位于 %LocalAppData% 下,因此我的分析如下:

  1. 该文件夹完全由我的应用程序控制,用户没有正当理由去将该文件夹内的内容标记为只读或不可访问,因此我不会尝试处理这种情况。

  2. 那里没有有价值的用户创建的东西,所以不存在错误地强行删除某些东西的风险。

  3. 作为一个内部数据文件夹,我不希望它在资源管理器中打开,至少我觉得不需要专门处理这个案例(即我可以通过支持来处理这个案例)。

  4. 如果所有尝试都失败,我选择忽略错误。最坏的情况是,该应用程序无法解压一些较新的资源,崩溃并提示用户联系支持人员,这对我来说是可以接受的,只要它不经常发生。或者,如果应用程序没有崩溃,它会留下一些旧数据,这也是我可以接受的。

  5. 我选择将重试时间限制为 500 毫秒(50 * 10)。这是一个在实践中有效的任意阈值;我希望阈值足够短,这样用户就不会认为应用程序已停止响应而终止应用程序。另一方面,半秒对于罪犯来说是足够的时间来完成我的文件夹的处理。从有时甚至Sleep(0)可以接受的其他 SO 答案来看,很少有用户会经历一次以上的重试。

  6. 我每 50 毫秒重试一次,这是另一个任意数字。我觉得如果在我尝试删除文件时正在处理(索引、检查)文件,那么 50ms 大约是预期处理在我的情况下完成的正确时间。此外,50ms 足够小,不会导致明显的减速;再次,Sleep(0)在很多情况下似乎已经足够了,所以我们不想耽误太多。

  7. 代码重试任何 IO 异常。我通常不会期望任何异常访问 %LocalAppData%,因此我选择了简单并接受了在发生合法异常时延迟 500 毫秒的风险。我也不想找到一种方法来检测我想要重试的确切异常。

于 2013-02-18T10:15:32.790 回答
20

现代异步答案

接受的答案是完全错误的,它可能对某些人有用,因为从磁盘获取文件所花费的时间释放了锁定文件的任何东西。事实是,发生这种情况是因为文件被其他一些进程/流/动作锁定。其他答案使用Thread.Sleep(Yuck)在一段时间后重试删除目录。这个问题需要用更现代的答案重新审视。

public static async Task<bool> TryDeleteDirectory(
   string directoryPath,
   int maxRetries = 10,
   int millisecondsDelay = 30)
{
    if (directoryPath == null)
        throw new ArgumentNullException(directoryPath);
    if (maxRetries < 1)
        throw new ArgumentOutOfRangeException(nameof(maxRetries));
    if (millisecondsDelay < 1)
        throw new ArgumentOutOfRangeException(nameof(millisecondsDelay));

    for (int i = 0; i < maxRetries; ++i)
    {
        try
        {
            if (Directory.Exists(directoryPath))
            {
                Directory.Delete(directoryPath, true);
            }

            return true;
        }
        catch (IOException)
        {
            await Task.Delay(millisecondsDelay);
        }
        catch (UnauthorizedAccessException)
        {
            await Task.Delay(millisecondsDelay);
        }
    }

    return false;
}

单元测试

这些测试显示了锁定文件如何导致Directory.Delete失败以及上述TryDeleteDirectory方法如何解决问题的示例。

[Fact]
public async Task TryDeleteDirectory_FileLocked_DirectoryNotDeletedReturnsFalse()
{
    var directoryPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
    var subDirectoryPath = Path.Combine(Path.GetTempPath(), "SubDirectory");
    var filePath = Path.Combine(directoryPath, "File.txt");

    try
    {
        Directory.CreateDirectory(directoryPath);
        Directory.CreateDirectory(subDirectoryPath);

        using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.Write))
        {
            var result = await TryDeleteDirectory(directoryPath, 3, 30);
            Assert.False(result);
            Assert.True(Directory.Exists(directoryPath));
        }
    }
    finally
    {
        if (Directory.Exists(directoryPath))
        {
            Directory.Delete(directoryPath, true);
        }
    }
}

[Fact]
public async Task TryDeleteDirectory_FileLockedThenReleased_DirectoryDeletedReturnsTrue()
{
    var directoryPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
    var subDirectoryPath = Path.Combine(Path.GetTempPath(), "SubDirectory");
    var filePath = Path.Combine(directoryPath, "File.txt");

    try
    {
        Directory.CreateDirectory(directoryPath);
        Directory.CreateDirectory(subDirectoryPath);

        Task<bool> task;
        using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.Write))
        {
            task = TryDeleteDirectory(directoryPath, 3, 30);
            await Task.Delay(30);
            Assert.True(Directory.Exists(directoryPath));
        }

        var result = await task;
        Assert.True(result);
        Assert.False(Directory.Exists(directoryPath));
    }
    finally
    {
        if (Directory.Exists(directoryPath))
        {
            Directory.Delete(directoryPath, true);
        }
    }
}
于 2017-06-02T08:33:11.563 回答
18

应该提到的一件重要的事情(我将其作为评论添加,但我不允许这样做)是重载的行为从 .NET 3.5 更改为 .NET 4.0。

Directory.Delete(myPath, true);

从 .NET 4.0 开始,它会删除文件夹本身中的文件,但不会删除 3.5 中的文件。这也可以在 MSDN 文档中看到。

.NET 4.0

删除指定目录以及目录中的任何子目录和文件(如果有指示)。

.NET 3.5

删除空目录以及目录中的任何子目录和文件(如果有指示)。

于 2016-11-24T14:38:00.323 回答
15

我在 Delphi 下遇到了同样的问题。最终结果是我自己的应用程序锁定了我要删除的目录。当我写入目录时,不知何故该目录被锁定(一些临时文件)。

第 22 个问题是,我在删除它之前对它的父级做了一个简单的更改目录。

于 2008-11-30T21:02:27.260 回答
12

您可以通过运行重现错误:

Directory.CreateDirectory(@"C:\Temp\a\b\c\");
Process.Start(@"C:\Temp\a\b\c\");
Thread.Sleep(1000);
Directory.Delete(@"C:\Temp\a\b\c");
Directory.Delete(@"C:\Temp\a\b");
Directory.Delete(@"C:\Temp\a");

当试图删除目录'b'时,它会抛出 IOException "The directory is not empty"。这很愚蠢,因为我们刚刚删除了目录“c”。

据我了解,解释是目录'c'被标记为已删除。但删除尚未在系统中提交。系统已回复作业已完成,实际上仍在处理中。系统可能会等待文件资源管理器关注父目录来提交删除。

如果您查看 Delete 函数的源代码 ( http://referencesource.microsoft.com/#mscorlib/system/io/directory.cs ),您会看到它使用了本机 Win32Native.RemoveDirectory 函数。这种不要等待的行为在此处注明:

RemoveDirectory 函数在关闭时标记要删除的目录。因此,在关闭该目录的最后一个句柄之前,不会删除该目录。

http://msdn.microsoft.com/en-us/library/windows/desktop/aa365488(v=vs.85).aspx

睡眠并重试是解决方案。参考 ryascl 的解决方案。

于 2014-09-05T08:06:12.860 回答
11

我很惊讶没有人想到这种简单的非递归方法,它可以删除包含只读文件的目录,而无需更改每个目录的只读属性。

Process.Start("cmd.exe", "/c " + @"rmdir /s/q C:\Test\TestDirectoryContainingReadOnlyFiles"); 

(稍微改变一下不要立即触发 cmd 窗口,这在整个互联网上都可用)

于 2012-06-02T05:54:17.447 回答
8

尽管能够在 Explorer shell 中删除用户配置文件目录(在 C:\Documents 和设置中),但我遇到了那些奇怪的权限问题。

File.SetAttributes(target_dir, FileAttributes.Normal);
Directory.Delete(target_dir, false);

对我来说,“文件”操作对目录的作用是没有意义的,但我知道它可以工作,这对我来说已经足够了!

于 2009-06-11T14:14:33.980 回答
3

不删除文件的递归目录删除肯定是出乎意料的。我的解决方法:

public class IOUtils
{
    public static void DeleteDirectory(string directory)
    {
        Directory.GetFiles(directory, "*", SearchOption.AllDirectories).ForEach(File.Delete);
        Directory.Delete(directory, true);
    }
}

我遇到过这有帮助的案例,但一般来说, Directory.Delete 在递归删除时会删除目录内的文件,如msdn 中所述

作为 Windows 资源管理器的用户,我有时也会遇到这种不正常的行为:有时我无法删除文件夹(它认为无意义的消息是“访问被拒绝”)但是当我向下钻取并删除较低的项目时,我可以删除上面的项目项目以及。所以我猜上面的代码处理的是操作系统异常——而不是基类库问题。

于 2013-05-01T15:38:31.813 回答
3

以上解决方案都不适合我。我最终使用了@ryascl 解决方案的编辑版本,如下所示:

    /// <summary>
    /// Depth-first recursive delete, with handling for descendant 
    /// directories open in Windows Explorer.
    /// </summary>
    public static void DeleteDirectory(string path)
    {
        foreach (string directory in Directory.GetDirectories(path))
        {
            Thread.Sleep(1);
            DeleteDir(directory);
        }
        DeleteDir(path);
    }

    private static void DeleteDir(string dir)
    {
        try
        {
            Thread.Sleep(1);
            Directory.Delete(dir, true);
        }
        catch (IOException)
        {
            DeleteDir(dir);
        }
        catch (UnauthorizedAccessException)
        {
            DeleteDir(dir);
        }
    }
于 2017-12-12T06:03:48.563 回答
3

此答案基于:https ://stackoverflow.com/a/1703799/184528 。与我的代码不同的是,我们只在必要时递归许多删除子目录和文件,第一次尝试调用 Directory.Delete 失败(这可能是由于 Windows 资源管理器查看目录而发生的)。

    public static void DeleteDirectory(string dir, bool secondAttempt = false)
    {
        // If this is a second try, we are going to manually 
        // delete the files and sub-directories. 
        if (secondAttempt)
        {
            // Interrupt the current thread to allow Explorer time to release a directory handle
            Thread.Sleep(0);

            // Delete any files in the directory 
            foreach (var f in Directory.GetFiles(dir, "*.*", SearchOption.TopDirectoryOnly))
                File.Delete(f);

            // Try manually recursing and deleting sub-directories 
            foreach (var d in Directory.GetDirectories(dir))
                DeleteDirectory(d);

            // Now we try to delete the current directory
            Directory.Delete(dir, false);
            return;
        }

        try
        {
            // First attempt: use the standard MSDN approach.
            // This will throw an exception a directory is open in explorer
            Directory.Delete(dir, true);
        }
        catch (IOException)
        {
            // Try again to delete the directory manually recursing. 
            DeleteDirectory(dir, true);
        }
        catch (UnauthorizedAccessException)
        {
            // Try again to delete the directory manually recursing. 
            DeleteDirectory(dir, true);
        } 
    }
于 2016-08-04T21:07:02.127 回答
2

您是否可能存在竞争条件,其中另一个线程或进程正在将文件添加到目录:

顺序是:

删除进程A:

  1. 清空目录
  2. 删除(现在为空)目录。

如果其他人在 1 和 2 之间添加了一个文件,那么也许 2 会抛出列出的异常?

于 2008-11-30T21:29:37.953 回答
2

我花了几个小时来解决这个问题和删除目录的其他异常。这是我的解决方案

 public static void DeleteDirectory(string target_dir)
    {
        DeleteDirectoryFiles(target_dir);
        while (Directory.Exists(target_dir))
        {
            lock (_lock)
            {
                DeleteDirectoryDirs(target_dir);
            }
        }
    }

    private static void DeleteDirectoryDirs(string target_dir)
    {
        System.Threading.Thread.Sleep(100);

        if (Directory.Exists(target_dir))
        {

            string[] dirs = Directory.GetDirectories(target_dir);

            if (dirs.Length == 0)
                Directory.Delete(target_dir, false);
            else
                foreach (string dir in dirs)
                    DeleteDirectoryDirs(dir);
        }
    }

    private static void DeleteDirectoryFiles(string target_dir)
    {
        string[] files = Directory.GetFiles(target_dir);
        string[] dirs = Directory.GetDirectories(target_dir);

        foreach (string file in files)
        {
            File.SetAttributes(file, FileAttributes.Normal);
            File.Delete(file);
        }

        foreach (string dir in dirs)
        {
            DeleteDirectoryFiles(dir);
        }
    }

这段代码有小的延迟,这对我的应用程序并不重要。但要小心,如果您要删除的目录中有很多子目录,延迟可能会给您带来问题。

于 2011-09-22T17:17:57.357 回答
2

您不必为递归创建额外的方法或删除额外文件夹内的文件。这一切都是通过调用自动完成的

DirectoryInfo.Delete();

详情在这里

像这样的东西很好用:

  var directoryInfo = new DirectoryInfo("My directory path");
    // Delete all files from app data directory.

    foreach (var subDirectory in directoryInfo.GetDirectories())
    {
          subDirectory.Delete(true);// true set recursive paramter, when it is true delete sub file and sub folder with files too
    }

将 true 作为变量传递给 delete 方法,也会删除子文件和带有文件的子文件夹。

于 2019-11-08T14:43:01.847 回答
1

目录或其中的文件被锁定,无法删除。找到锁定它的罪魁祸首,看看你是否可以消除它。

于 2008-11-30T21:31:21.413 回答
1

这是因为FileChangesNotifications。

它发生在 ASP.NET 2.0 之后。当您删除应用程序中的某个文件夹时,它会重新启动。您可以使用 ASP.NET Health Monitoring自己查看。

只需将此代码添加到您的 web.config/configuration/system.web:

<healthMonitoring enabled="true">
  <rules>
    <add name="MyAppLogEvents" eventName="Application Lifetime Events" provider="EventLogProvider" profile="Critical"/>
  </rules>
</healthMonitoring>


之后退房Windows Log -> Application。到底是怎么回事:

删除文件夹时,如果有子文件夹,Delete(path, true)先删除子文件夹。FileChangesMonitor 知道删除和关闭您的应用程序就足够了。同时你的主目录还没有被删除。这是来自日志的事件:


在此处输入图像描述


Delete()没有完成它的工作,因为应用程序正在关闭,它引发了一个异常:

在此处输入图像描述

当您要删除的文件夹中没有任何子文件夹时,Delete() 只会删除所有文件和该文件夹,应用程序也会重新启动,但您不会遇到任何异常,因为应用程序重新启动不会中断任何事情。但是,您仍然会丢失所有进程中的会话,应用程序在重新启动时不响应请求等。

现在怎么办?

有一些变通方法和调整可以禁用此行为,Directory Junction使用 Registry 关闭 FCN,使用Reflection 停止 FileChangesMonitor(因为没有暴露的方法),但它们似乎都不正确,因为 FCN 存在原因。它负责您的应用程序的结构,而不是您的数据结构。简短的回答是:将要删除的文件夹放在应用程序之外。FileChangesMonitor 不会收到任何通知,并且您的应用程序不会每次都重新启动。你不会有任何例外。要让它们从网络上可见,有两种方法:

  1. 制作一个控制器来处理来电,然后通过从应用程序外部(wwwroot 外部)的文件夹中读取来返回文件。

  2. 如果您的项目很大并且性能最重要,请设置单独的小型快速网络服务器来提供静态内容。因此,您将把他的具体工作留给 IIS。它可以在同一台机器上(Windows 的猫鼬)或另一台机器(Linux 的 nginx)。好消息是您无需支付额外的 microsoft 许可证即可在 linux 上设置静态内容服务器。

希望这可以帮助。

于 2013-11-26T10:39:33.890 回答
1

似乎在 Windows 资源管理器中选择路径或子文件夹足以阻止 Directory.Delete(path, true) 的单次执行,如上所述抛出 IOException 并死掉,而不是将 Windows 资源管理器引导到父文件夹并作为预期的。

于 2010-02-24T19:32:40.440 回答
1

I've had this same problem with Windows Workflow Foundation on a build server with TFS2012. Internally, the workflow called Directory.Delete() with the recursive flag set to true. It appears to be network related in our case.

We were deleting a binary drop folder on a network share before re-creating and re-populating it with the latest binaries. Every other build would fail. When opening the drop folder after a failed build, the folder was empty, which indicates that every aspect of the Directory.Delete() call was successful except for deleting the actually directory.

The problem appears to be caused by the asynchronous nature of network file communications. The build server told the file server to delete all of the files and the file server reported that it had, even though it wasn't completely finished. Then the build server requested that the directory be deleted and the file server rejected the request because it hadn't completely finished deleting the files.

Two possible solutions in our case:

  • Build up the recursive deletion in our own code with delays and verifications between each step
  • Retry up to X times after an IOException, giving a delay before trying again

The latter method is quick and dirty but seems to do the trick.

于 2013-07-24T15:28:43.557 回答
1

我今天遇到了这个问题。发生这种情况是因为我将 Windows 资源管理器打开到试图被删除的目录,导致递归调用失败,从而导致 IOException。确保没有打开该目录的句柄。

此外,MSDN 很清楚您不必编写自己的回避:http: //msdn.microsoft.com/en-us/library/fxeahc5f.aspx

于 2011-03-28T22:07:31.180 回答
1

如上所述,“已接受”解决方案在重解析点上失败。有一个更短的解决方案可以正确复制功能:

public static void rmdir(string target, bool recursive)
{
    string tfilename = Path.GetDirectoryName(target) +
        (target.Contains(Path.DirectorySeparatorChar.ToString()) ? Path.DirectorySeparatorChar.ToString() : string.Empty) +
        Path.GetRandomFileName();
    Directory.Move(target, tfilename);
    Directory.Delete(tfilename, recursive);
}

我知道,不处理后面提到的权限情况,但出于所有意图和目的,FAR BETTER 提供了原始/库存 Directory.Delete()的预期功能- 并且代码也少了很多

您可以安全地继续处理,因为旧目录将不受影响 ......即使因为“文件系统仍在追赶”(或 MS 提供的提供损坏功能的任何借口)而没有消失

作为一个好处,如果您知道您的目标目录很大/很深并且不想等待(或为异常而烦恼)最后一行可以替换为:

    ThreadPool.QueueUserWorkItem((o) => { Directory.Delete(tfilename, recursive); });

你仍然可以安全地继续工作。

于 2015-07-21T05:44:34.203 回答
1

我已经用这种千年技术解决了(你可以把 Thread.Sleep 留在他自己的陷阱中)

bool deleted = false;
        do
        {
            try
            {
                Directory.Delete(rutaFinal, true);                    
                deleted = true;
            }
            catch (Exception e)
            {
                string mensaje = e.Message;
                if( mensaje == "The directory is not empty.")
                Thread.Sleep(50);
            }
        } while (deleted == false);
于 2018-10-29T19:37:21.933 回答
1

当目录(或任何子目录)中存在路径长度大于 260 个符号的文件时,此问题可能会出现在 Windows 上。

在这种情况下,您需要删除\\\\?\C:\mydir而不是C:\mydir. 关于 260 个符号的限制,您可以在此处阅读。

于 2016-11-11T14:34:43.347 回答
0

如果您的应用程序(或任何其他应用程序)的当前目录是您要删除的目录,则它不会是访问冲突错误,但目录不为空。通过更改当前目录确保它不是您自己的应用程序;另外,请确保该目录未在其他程序中打开(例如 Word、excel、Total Commander 等)。大多数程序将 cd 到最后打开的文件的目录,这会导致这种情况。

于 2008-11-30T23:38:10.473 回答
0

如果是网络文件,Directory.DeleteHelper(recursive:=true) 可能会导致删除文件延迟导致的IOException

于 2011-03-03T02:12:05.770 回答
0

当方法异步并像这样编码时,我解决了上述问题的一个可能实例:

// delete any existing update content folder for this update
if (await fileHelper.DirectoryExistsAsync(currentUpdateFolderPath))
       await fileHelper.DeleteDirectoryAsync(currentUpdateFolderPath);

有了这个:

bool exists = false;                
if (await fileHelper.DirectoryExistsAsync(currentUpdateFolderPath))
    exists = true;

// delete any existing update content folder for this update
if (exists)
    await fileHelper.DeleteDirectoryAsync(currentUpdateFolderPath);

结论?摆脱用于检查 Microsoft 无法与之交谈的存在的句柄有一些异步方面。就好像 if 语句中的异步方法具有 if 语句的作用类似于 using 语句。

于 2016-10-28T18:51:15.460 回答
-2

以上答案都不适合我。看来我自己的应用程序DirectoryInfo在目标目录上的使用导致它保持锁定状态。

强制垃圾收集似乎可以解决问题,但不是马上。在需要的地方进行了几次删除尝试。

请注意,Directory.Exists因为它可以在异常后消失。我不知道为什么我的删除被延迟(Windows 7 SP1)

        for (int attempts = 0; attempts < 10; attempts++)
        {
            try
            {
                if (Directory.Exists(folder))
                {
                    Directory.Delete(folder, true);
                }
                return;
            }
            catch (IOException e)
            {
                GC.Collect();
                Thread.Sleep(1000);
            }
        }

        throw new Exception("Failed to remove folder.");
于 2013-12-06T18:07:31.440 回答