我需要删除包含只读文件的目录。哪种方法更好:
使用DirectoryInfo.Delete()
,或
ManagementObject.InvokeMethod("Delete")
?
使用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)
{
}
}
答案 0 :(得分:92)
避免递归调用的最简单方法是在获取AllDirectories
时使用FileSystemInfo
选项,如下所示:
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);
}
答案 1 :(得分:87)
这是一种扩展方法,可以递归地将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();
}
答案 2 :(得分:9)
试试这个,
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);
}
答案 3 :(得分:5)
另一种不需要递归的方法。
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);
}
答案 4 :(得分:3)
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();
}
答案 5 :(得分:2)
最佳解决方案是将所有文件标记为非读取,然后删除目录。
// 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));
注意〜是一个按位逻辑运算符,它返回给定二进制值的补码。我没有测试过这个,但它应该可以工作。
谢谢!
答案 6 :(得分:1)
我会说你的第一种方法看起来更明确和可读。第二种方法闻起来像反射,不是类型安全的,看起来很奇怪。 ManagementObject
可以表示多个内容,因此.InvokeMethod("Delete")
实际删除目录并不明显。
答案 7 :(得分:1)
我不喜欢第一种方法(directory.delete)的情况是存在包含只读文件的子目录,并且它们的子目录也包含只读文件,因此上。看起来你必须为目录中的每个文件和递归的所有子目录关闭该标志。
使用第二种方法,您可以删除第一个目录,但不检查文件是否为只读。但是,这是我第一次在C#中使用WMI,所以我对它并不是很满意。所以我不确定何时将WMI方法用于其他应用程序,而不是仅仅使用System.IO方法。
答案 8 :(得分:0)
从表面上看,使用WMI方法似乎比在整个文件系统上进行迭代更有效(例如,假设该目录包含10个数千个文件)。但我不知道WMI也不做迭代。如果确实如此,那么更接近金属(再次,假设)它应该更有效率。
为了优雅,我承认递归方法很酷。
性能测试应该回答效率问题。如果包含在DirectoryInfo的扩展方法中,则要么优雅。
答案 9 :(得分:0)
这是另一种避免递归的解决方案。
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。
在相关的说明中,虽然这有效,但我在删除“太长”的路径时遇到了问题,并最终使用此处发布的robocopy解决方案:C# deleting a folder that has long paths
答案 10 :(得分:0)
为了跟进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();
}
答案 11 :(得分:0)
我针对 NET 框架 3.5 和 NET 框架版本 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();