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

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

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

  • ManagementObject.InvokeMethod("Delete")

DirectoryInfo.Delete() ,我必须手动closures每个文件的只读属性,但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) { } } 

这是一个扩展方法,它将Attributesrecursion设置为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(); } 

避免recursion调用的最简单方法是在获取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); } 

尝试这个,

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

另一种方法不需要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); } 
 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(); } 

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

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

请注意,〜是一个按位逻辑运算符,它返回给定二进制值的补码。 我没有testing过这个,但是应该可以。

谢谢!

我会说,你的第一个方法看起来更加明确和可读性。 第二种方法闻起来像reflection,不安全,看起来很奇怪。 ManagementObject可以表示多个东西,所以不明显.InvokeMethod("Delete")实际上删除了一个目录。

我不喜欢关于第一种方法(directory.delete)的事情是有子目录也包含只读文件,并且它们也有只读文件的子目录等等。 好像你必须closures该目录中的每个文件和所有子目录recursion的标志。

通过第二种方法,您可以删除第一个目录,而不检查文件是否是只读的。 不过,这是我第一次在C#中使用WMI,所以我并不是那么满意。 所以我不确定何时使用其他应用程序的WMI方法,而不是使用System.IO方法。

从表面上看,使用WMI方法似乎比遍历整个文件系统更有效率(假设目录有数千个文件)。 但是我不知道WMI也不会做迭代。 如果是这样,接近金属(再次假设)应该更有效率。

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

性能testing应该回答效率问题。 如果用DirectoryInfo的扩展方法包装,可以是优雅的。

这是避免自身recursion的另一个解决scheme。

 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”方法的最后一行,并单独使用delete。

在一个相关的说明,虽然这个工作,然后我有问题,删除“太长”的path,并最终使用robocopy解决scheme张贴在这里: C#删除一个文件夹,有长path

为了跟上Vitaliy Ulantikov的解决scheme,我补充了一个重命名/移动文件夹方法:

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