如何在C#中删除包含只读文件的目录?

发布于 2024-07-15 08:02:15 字数 1511 浏览 12 评论 0原文

我需要删除包含只读文件的目录。 哪种方法更好:

  • 使用DirectoryInfo.Delete(),或者,

  • ManagementObject.InvokeMethod("删除")

使用 DirectoryInfo.Delete(),我必须手动关闭每个文件的只读属性,但 ManagementObject.InvokeMethod("Delete") 似乎没有需要。 是否存在一种情况比另一种更可取的情况?

示例代码(test.txt 是只读的)。

第一种方式:

DirectoryInfo dir = new DirectoryInfo(@"C:\Users\David\Desktop\");
dir.CreateSubdirectory("Test");

DirectoryInfo test = new DirectoryInfo(@"C:\Users\David\Desktop\Test\");
File.Copy(@"C:\Users\David\Desktop\test.txt", @"C:\Users\David\Desktop\Test\test.txt");
File.SetAttributes(@"C:\Users\David\Desktop\Test\test.txt", FileAttributes.Archive);
test.Delete(true);

第二种方式:

DirectoryInfo dir = new DirectoryInfo(@"C:\Users\David\Desktop\");
dir.CreateSubdirectory("Test");

DirectoryInfo test = new DirectoryInfo(@"C:\Users\David\Desktop\Test\");
File.Copy(@"C:\Users\David\Desktop\test.txt", @"C:\Users\David\Desktop\Test\test.txt");

string folder = @"C:\Users\David\Desktop\Test";
string dirObject = "Win32_Directory.Name='" + folder + "'";
using (ManagementObject managementObject = new ManagementObject(dirObject))
{
    managementObject.Get();
    ManagementBaseObject outParams = managementObject.InvokeMethod("Delete", null,
    null);
    // ReturnValue should be 0, else failure
    if (Convert.ToInt32(outParams.Properties["ReturnValue"].Value) != 0)
    {
    }
}

I need to delete a directory that contains read-only files. Which approach is better:

  • Using DirectoryInfo.Delete(), or,

  • ManagementObject.InvokeMethod("Delete")?

With DirectoryInfo.Delete(), I have to manually turn off the read-only attribute for each file, but ManagementObject.InvokeMethod("Delete") doesn't appear to need to. Is there any situation where one is more preferable to the other?

Sample code (test.txt is read only).

First way:

DirectoryInfo dir = new DirectoryInfo(@"C:\Users\David\Desktop\");
dir.CreateSubdirectory("Test");

DirectoryInfo test = new DirectoryInfo(@"C:\Users\David\Desktop\Test\");
File.Copy(@"C:\Users\David\Desktop\test.txt", @"C:\Users\David\Desktop\Test\test.txt");
File.SetAttributes(@"C:\Users\David\Desktop\Test\test.txt", FileAttributes.Archive);
test.Delete(true);

Second way:

DirectoryInfo dir = new DirectoryInfo(@"C:\Users\David\Desktop\");
dir.CreateSubdirectory("Test");

DirectoryInfo test = new DirectoryInfo(@"C:\Users\David\Desktop\Test\");
File.Copy(@"C:\Users\David\Desktop\test.txt", @"C:\Users\David\Desktop\Test\test.txt");

string folder = @"C:\Users\David\Desktop\Test";
string dirObject = "Win32_Directory.Name='" + folder + "'";
using (ManagementObject managementObject = new ManagementObject(dirObject))
{
    managementObject.Get();
    ManagementBaseObject outParams = managementObject.InvokeMethod("Delete", null,
    null);
    // ReturnValue should be 0, else failure
    if (Convert.ToInt32(outParams.Properties["ReturnValue"].Value) != 0)
    {
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

好听的两个字的网名 2024-07-22 08:02:16

为了跟进 Vitaliy Ulantikov 的解决方案,我用重命名/移动文件夹方法对其进行了补充:

  public static void renameFolder(String sourcePath, String targetPath) {
     try
     {
        if (System.IO.Directory.Exists(targetPath))
           DeleteFileSystemInfo(new DirectoryInfo(targetPath));
        System.IO.Directory.Move(sourcePath, targetPath);
     }
     catch (Exception ex)
     {
        Console.WriteLine("renameFolder: " + sourcePath + " " + targetPath + " " + ex.Message);
        throw ex;
     }
  }

  private static void DeleteFileSystemInfo(FileSystemInfo fsi) {
     fsi.Attributes = FileAttributes.Normal;
     var di = fsi as DirectoryInfo;

     if (di != null)
     {
        foreach (var dirInfo in di.GetFileSystemInfos())
        {
           DeleteFileSystemInfo(dirInfo);
        }
     }

     fsi.Delete();
  }

To follow up on Vitaliy Ulantikov's solution I have supplemented it with a rename/move folder method:

  public static void renameFolder(String sourcePath, String targetPath) {
     try
     {
        if (System.IO.Directory.Exists(targetPath))
           DeleteFileSystemInfo(new DirectoryInfo(targetPath));
        System.IO.Directory.Move(sourcePath, targetPath);
     }
     catch (Exception ex)
     {
        Console.WriteLine("renameFolder: " + sourcePath + " " + targetPath + " " + ex.Message);
        throw ex;
     }
  }

  private static void DeleteFileSystemInfo(FileSystemInfo fsi) {
     fsi.Attributes = FileAttributes.Normal;
     var di = fsi as DirectoryInfo;

     if (di != null)
     {
        foreach (var dirInfo in di.GetFileSystemInfos())
        {
           DeleteFileSystemInfo(dirInfo);
        }
     }

     fsi.Delete();
  }
赠佳期 2024-07-22 08:02:16

我针对 NET Framework 3.5 和 NET Framework 版本 4 及更高版本的解决方案:

#region DeleteWithReadOnly
internal static void DeleteWithReadOnly(this DirectoryInfo di)
{
   foreach (FileSystemInfo fsi in di.EnumerateFileSystemInfos("*", SearchOption.AllDirectories))
   {
      fsi.Attributes = FileAttributes.Normal;
   }
   di.Delete(true);
}
#endregion

#region DeleteWithReadOnlyNET3_5
internal static void DeleteWithReadOnlyNET3_5(this DirectoryInfo di)
{
   foreach (FileSystemInfo fsi in di.GetFiles("*", SearchOption.AllDirectories))
   {
      fsi.Attributes = FileAttributes.Normal;
   }
   di.Delete(true);
}
#endregion

用法:

DirectoryInfo di = new DirectoryInfo(@"C:\TMP");
di.DeleteWithReadOnly();

My solution for NET framework 3.5 and for NET framework version 4 and higher:

#region DeleteWithReadOnly
internal static void DeleteWithReadOnly(this DirectoryInfo di)
{
   foreach (FileSystemInfo fsi in di.EnumerateFileSystemInfos("*", SearchOption.AllDirectories))
   {
      fsi.Attributes = FileAttributes.Normal;
   }
   di.Delete(true);
}
#endregion

#region DeleteWithReadOnlyNET3_5
internal static void DeleteWithReadOnlyNET3_5(this DirectoryInfo di)
{
   foreach (FileSystemInfo fsi in di.GetFiles("*", SearchOption.AllDirectories))
   {
      fsi.Attributes = FileAttributes.Normal;
   }
   di.Delete(true);
}
#endregion

Usage:

DirectoryInfo di = new DirectoryInfo(@"C:\TMP");
di.DeleteWithReadOnly();
灯下孤影 2024-07-22 08:02:15

避免递归调用的最简单方法是在获取 FileSystemInfo 时使用 AllDirectories 选项,如下所示:

public static void ForceDeleteDirectory(string path) 
{
    var directory = new DirectoryInfo(path) { Attributes = FileAttributes.Normal };

    foreach (var info in directory.GetFileSystemInfos("*", SearchOption.AllDirectories))
    {
        info.Attributes = FileAttributes.Normal;
    }

    directory.Delete(true);
}

Simplest way of avoiding recursive calls is by utilising the AllDirectories option when getting FileSystemInfos, like so:

public static void ForceDeleteDirectory(string path) 
{
    var directory = new DirectoryInfo(path) { Attributes = FileAttributes.Normal };

    foreach (var info in directory.GetFileSystemInfos("*", SearchOption.AllDirectories))
    {
        info.Attributes = FileAttributes.Normal;
    }

    directory.Delete(true);
}
就此别过 2024-07-22 08:02:15

这是一个扩展方法,它递归地将 Attributes 设置为 Normal,然后删除项目:

public static void DeleteReadOnly(this FileSystemInfo fileSystemInfo)
{
    var directoryInfo = fileSystemInfo as DirectoryInfo;    
    if (directoryInfo != null)
    {
        foreach (FileSystemInfo childInfo in directoryInfo.GetFileSystemInfos())
        {
            childInfo.DeleteReadOnly();
        }
    }

    fileSystemInfo.Attributes = FileAttributes.Normal;
    fileSystemInfo.Delete();
}

Here is an extension method which sets Attributes to Normal recursively, then deletes the items:

public static void DeleteReadOnly(this FileSystemInfo fileSystemInfo)
{
    var directoryInfo = fileSystemInfo as DirectoryInfo;    
    if (directoryInfo != null)
    {
        foreach (FileSystemInfo childInfo in directoryInfo.GetFileSystemInfos())
        {
            childInfo.DeleteReadOnly();
        }
    }

    fileSystemInfo.Attributes = FileAttributes.Normal;
    fileSystemInfo.Delete();
}
混吃等死 2024-07-22 08:02:15

尝试这个,

private void DeleteRecursiveFolder(string pFolderPath)
{
    foreach (string Folder in Directory.GetDirectories(pFolderPath))
    {
        DeleteRecursiveFolder(Folder);
    }

    foreach (string file in Directory.GetFiles(pFolderPath))
    {
        var pPath = Path.Combine(pFolderPath, file);
        FileInfo fi = new FileInfo(pPath);
        File.SetAttributes(pPath, FileAttributes.Normal);
        File.Delete(file);
    }

    Directory.Delete(pFolderPath);
}

Try this,

private void DeleteRecursiveFolder(string pFolderPath)
{
    foreach (string Folder in Directory.GetDirectories(pFolderPath))
    {
        DeleteRecursiveFolder(Folder);
    }

    foreach (string file in Directory.GetFiles(pFolderPath))
    {
        var pPath = Path.Combine(pFolderPath, file);
        FileInfo fi = new FileInfo(pPath);
        File.SetAttributes(pPath, FileAttributes.Normal);
        File.Delete(file);
    }

    Directory.Delete(pFolderPath);
}
晒暮凉 2024-07-22 08:02:15

另一种方法不需要递归。

public static void ForceDeleteDirectory(string path)
{
    DirectoryInfo root;
    Stack<DirectoryInfo> fols;
    DirectoryInfo fol;
    fols = new Stack<DirectoryInfo>();
    root = new DirectoryInfo(path);
    fols.Push(root);
    while (fols.Count > 0)
    {
        fol = fols.Pop();
        fol.Attributes = fol.Attributes & ~(FileAttributes.Archive | FileAttributes.ReadOnly | FileAttributes.Hidden);
        foreach (DirectoryInfo d in fol.GetDirectories())
        {
            fols.Push(d);
        }
        foreach (FileInfo f in fol.GetFiles())
        {
            f.Attributes = f.Attributes & ~(FileAttributes.Archive | FileAttributes.ReadOnly | FileAttributes.Hidden);
            f.Delete();
        }
    }
    root.Delete(true);
}

Another method without the need for recursion.

public static void ForceDeleteDirectory(string path)
{
    DirectoryInfo root;
    Stack<DirectoryInfo> fols;
    DirectoryInfo fol;
    fols = new Stack<DirectoryInfo>();
    root = new DirectoryInfo(path);
    fols.Push(root);
    while (fols.Count > 0)
    {
        fol = fols.Pop();
        fol.Attributes = fol.Attributes & ~(FileAttributes.Archive | FileAttributes.ReadOnly | FileAttributes.Hidden);
        foreach (DirectoryInfo d in fol.GetDirectories())
        {
            fols.Push(d);
        }
        foreach (FileInfo f in fol.GetFiles())
        {
            f.Attributes = f.Attributes & ~(FileAttributes.Archive | FileAttributes.ReadOnly | FileAttributes.Hidden);
            f.Delete();
        }
    }
    root.Delete(true);
}
幸福丶如此 2024-07-22 08:02:15
private void DeleteRecursiveFolder(DirectoryInfo dirInfo)
{
    foreach (var subDir in dirInfo.GetDirectories())
    {
        DeleteRecursiveFolder(subDir);
    }

    foreach (var file in dirInfo.GetFiles())
    {
        file.Attributes=FileAttributes.Normal;
        file.Delete();
    }

    dirInfo.Delete();
}
private void DeleteRecursiveFolder(DirectoryInfo dirInfo)
{
    foreach (var subDir in dirInfo.GetDirectories())
    {
        DeleteRecursiveFolder(subDir);
    }

    foreach (var file in dirInfo.GetFiles())
    {
        file.Attributes=FileAttributes.Normal;
        file.Delete();
    }

    dirInfo.Delete();
}
無心 2024-07-22 08:02:15

最好的解决方案是将所有文件标记为非只读,然后删除该目录。

// delete/clear hidden attribute
File.SetAttributes(filePath, File.GetAttributes(filePath) & ~FileAttributes.Hidden);

// delete/clear archive and read only attributes
File.SetAttributes(filePath, File.GetAttributes(filePath) 
    & ~(FileAttributes.Archive | FileAttributes.ReadOnly));

请注意,~ 是一个按位逻辑运算符,它返回给定二进制值的补码。 我还没有测试过这个,但它应该有效。

谢谢!

The best solution is to mark all the files as non-read only, and then delete the directory.

// delete/clear hidden attribute
File.SetAttributes(filePath, File.GetAttributes(filePath) & ~FileAttributes.Hidden);

// delete/clear archive and read only attributes
File.SetAttributes(filePath, File.GetAttributes(filePath) 
    & ~(FileAttributes.Archive | FileAttributes.ReadOnly));

Notice that ~ is a Bitwise logical operator which returns the complement of the given binary value. I haven't tested this, but it should work.

Thanks!

ㄖ落Θ余辉 2024-07-22 08:02:15

我想说你的第一种方法看起来更明确和可读。 第二种方法闻起来像反射,不是类型安全的,而且看起来很奇怪。 ManagementObject 可以代表多个事物,因此 .InvokeMethod("Delete") 实际上删除一个目录并不明显。

I would say that your first approach looks more explicit and readable. The second method smells like reflection, is not type safe and looks weird. The ManagementObject can represent multiple things, so it's not obvious that .InvokeMethod("Delete") actually deletes a directory.

溇涏 2024-07-22 08:02:15

从表面上看,使用 WMI 方法似乎比迭代整个文件系统更有效(例如假设目录有数十个或数千个文件)。 但我不知道WMI也不做迭代。 如果确实如此,那么更接近金属(再次假设)它应该会更有效。

为了优雅,我承认递归方法很酷。

性能测试应该回答效率问题。 如果包装在 DirectoryInfo 的扩展方法中,这两种方法都可以很优雅。

On the surface, using the WMI approach seems more efficient than iterating over the entire file system (assume for example the directory has 10's of thousands of files). But I do not know that WMI also doesn't do iterations. If it does, being closer to the metal (again, assumptions) it should be more efficient.

For elegance, I concede the recursive method is cool.

Performance testing should answer the efficiency question. And either can be elegant if wrapped in an extension method of DirectoryInfo.

如歌彻婉言 2024-07-22 08:02:15

这是另一种避免自身递归的解决方案。

public static void DirectoryDeleteAll(string directoryPath)
{
    var rootInfo = new DirectoryInfo(directoryPath) { Attributes = FileAttributes.Normal };
    foreach (var fileInfo in rootInfo.GetFileSystemInfos()) fileInfo.Attributes = FileAttributes.Normal;
    foreach (var subDirectory in Directory.GetDirectories(directoryPath, "*", SearchOption.AllDirectories))
    {
        var subInfo = new DirectoryInfo(subDirectory) { Attributes = FileAttributes.Normal };
        foreach (var fileInfo in subInfo.GetFileSystemInfos()) fileInfo.Attributes = FileAttributes.Normal;
    }
    Directory.Delete(directoryPath, true);
}

这是通过在删除之前重置文件夹和文件的属性来实现的,因此您只需删除“DirectoryResetAttributes”方法的最后一行并单独使用删除即可。

与此相关的是,虽然这有效,但我在删除“太长”的路径时遇到了问题,最终使用了此处发布的 robocopy 解决方案: C# 删除具有长路径的文件夹

Here is another solution that avoids recursion on itself.

public static void DirectoryDeleteAll(string directoryPath)
{
    var rootInfo = new DirectoryInfo(directoryPath) { Attributes = FileAttributes.Normal };
    foreach (var fileInfo in rootInfo.GetFileSystemInfos()) fileInfo.Attributes = FileAttributes.Normal;
    foreach (var subDirectory in Directory.GetDirectories(directoryPath, "*", SearchOption.AllDirectories))
    {
        var subInfo = new DirectoryInfo(subDirectory) { Attributes = FileAttributes.Normal };
        foreach (var fileInfo in subInfo.GetFileSystemInfos()) fileInfo.Attributes = FileAttributes.Normal;
    }
    Directory.Delete(directoryPath, true);
}

This works by resettings attributes on the folders and files before the delete, so you could just remove the last line for a 'DirectoryResetAttributes' method and use delete separately.

On a related note, while this worked, I then had issues with deleting paths that were 'too long' and ended up using a robocopy solution posted here: C# deleting a folder that has long paths

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文