Cannot delete directory with Directory.Delete(path

2019-01-01 03:17发布

I'm using .NET 3.5, trying to recursively delete a directory using:

Directory.Delete(myPath, true);

My understanding is that this should throw if files are in use or there is a permissions problem, but otherwise it should delete the directory and all of its contents.

However, I occasionally get this:

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)
    ...

I'm not surprised that the method sometimes throws, but I'm surprised to get this particular message when recursive is true. (I know the directory is not empty.)

Is there a reason I'd see this instead of AccessViolationException?

29条回答
还给你的自由
2楼-- · 2019-01-01 03:32

The directory or a file in it is locked and cannot be deleted. Find the culprit who locks it and see if you can eliminate it.

查看更多
初与友歌
3楼-- · 2019-01-01 03:32

Non of above solutions worked well for me. I ended up by using an edited version of @ryascl solution as below:

    /// <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);
        }
    }
查看更多
孤独寂梦人
4楼-- · 2019-01-01 03:33

I had the very same problem under Delphi. And the end result was that my own application was locking the directory I wanted to delete. Somehow the directory got locked when I was writing to it (some temporary files).

The catch 22 was, I made a simple change directory to it's parent before deleting it.

查看更多
只若初见
5楼-- · 2019-01-01 03:33

None of the above answers worked for me. It appears that my own app's usage of DirectoryInfo on the target directory was causing it to remain locked.

Forcing garbage collection appeared to resolve the issue, but not right away. A few attempts to delete where required.

Note the Directory.Exists as it can disappear after an exception. I don't know why the delete for me was delayed (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.");
查看更多
牵手、夕阳
6楼-- · 2019-01-01 03:34

I have spent few hours to solve this problem and other exceptions with deleting the directory. This is my solution

 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);
        }
    }

This code has the small delay, which is not important for my application. But be careful, the delay may be a problem for you if you have a lot of subdirectories inside the directory you want to delete.

查看更多
大哥的爱人
7楼-- · 2019-01-01 03:34

As mentioned above the "accepted" solution fails on reparse points - yet people still mark it up(???). There's a much shorter solution that properly replicates the functionality:

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);
}

I know, doesn't handle the permissions cases mentioned later, but for all intents and purposes FAR BETTER provides the expected functionality of the original/stock Directory.Delete() - and with a lot less code too.

You can safely carry on processing because the old dir will be out of the way ...even if not gone because the 'file system is still catching up' (or whatever excuse MS gave for providing a broken function).

As a benefit, if you know your target directory is large/deep and don't want to wait (or bother with exceptions) the last line can be replaced with:

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

You are still safe to carry on working.

查看更多
登录 后发表回答