重启时删除非空文件夹

时间:2014-01-13 17:38:02

标签: c# winapi movefileex

我尝试从域中删除用户后删除Users文件夹中的用户个人资料文件夹。问题是有时系统可能正在使用该文件夹。

问题是使用MOVEFILE_DELAY_UNTIL_REBOOT MoveFileEx只会删除空文件夹。

From the MSDN

  

如果 dwFlags 指定 MOVEFILE_DELAY_UNTIL_REBOOT lpNewFileName NULL ,则MoveFileEx会注册 lpExistingFileName 系统重启时要删除的文件。如果 lpExistingFileName 引用目录,则仅当目录为空时,系统才会在重新启动时删除目录。

删除正在使用其中的文件的非空文件夹的正确方法是什么?


这是一个基于Michel答案的简单测试程序,它按预期工作。

internal static class Program
{
    private static void Main(string[] args)
    {
        foreach (var file in Directory.EnumerateFiles(args[0], "*", SearchOption.AllDirectories))
        {
            Console.WriteLine(file);
        }

        foreach (var directory in Directory.EnumerateDirectories(args[0], "*", SearchOption.AllDirectories))
        {
            Console.WriteLine(directory);
            DeleteFileOnReboot(directory);
        }

        DeleteFileOnReboot(args[0]);
    }

    private static void DeleteFileOnReboot(string file)
    {
        bool result = MoveFileEx(file, null, MoveFileFlags.MOVEFILE_DELAY_UNTIL_REBOOT);
        try
        {
            if (!result)
                throw new Win32Exception();
        }
        catch (Win32Exception ex)
        {
            Console.WriteLine(ex);
        }
    }

    [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    static extern bool MoveFileEx(string lpExistingFileName, string lpNewFileName, MoveFileFlags dwFlags);

}

[Flags]
enum MoveFileFlags
{
    MOVEFILE_REPLACE_EXISTING = 0x00000001,
    MOVEFILE_COPY_ALLOWED = 0x00000002,
    MOVEFILE_DELAY_UNTIL_REBOOT = 0x00000004,
    MOVEFILE_WRITE_THROUGH = 0x00000008,
    MOVEFILE_CREATE_HARDLINK = 0x00000010,
    MOVEFILE_FAIL_IF_NOT_TRACKABLE = 0x00000020
}

我在Directory.EnumerateFilesDirectory.EnumerateDirectories的两个循环中执行此操作,因为Directory.EnumerateFileSystemEntries会在文件夹中的文件之前列出文件夹,因此删除会失败。

2 个答案:

答案 0 :(得分:6)

在我见过的大多数实现中,目录中的每个文件都被MoveFileExMOVEFILE_DELAY_UNTIL_REBOOT“删除”,然后以同样的方式“删除”目录。重新启动时保留操作顺序 - 首先删除文件,然后删除目录。

答案 1 :(得分:2)

我同意Michael Gunter的回答。刚刚添加的代码示例就是迈克尔建议的那样。

public class Cleanuper
{
    private void PendingDeleteDirectory(string directoryPath)
    {
        foreach (string directory in Directory.GetDirectories(directoryPath, "*", SearchOption.TopDirectoryOnly))
        {
            PendingDeleteDirectory(directory);
        }

        foreach (string file in Directory.GetFiles(directoryPath, "*", SearchOption.TopDirectoryOnly))
        {
            NativeMethods.MoveFileEx(file, null, MoveFileFlags.DelayUntilReboot);
        }
        NativeMethods.MoveFileEx(directoryPath, null, MoveFileFlags.DelayUntilReboot);
    }
}

public static class NativeMethods
{
    [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    internal static extern bool MoveFileEx(string lpExistingFileName, string lpNewFileName, MoveFileFlags dwFlags);
}

[Flags]
public enum MoveFileFlags
{
    DelayUntilReboot = 0x00000004
}