문제

읽기 전용 파일이 포함 된 디렉토리를 삭제해야합니다. 어떤 접근법이 더 나은지 :

  • 사용 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)
    {
    }
}
도움이 되었습니까?

해결책

다음은 설정하는 확장 방법입니다 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();
}

다른 팁

재귀적인 전화를 피하는 가장 간단한 방법은 AllDirectories 얻을 때 옵션 FileSystemInfoS, 그렇게 :

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

재귀가 필요없는 또 다른 방법.

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

~는 주어진 이진 값의 보완을 반환하는 약간의 논리 연산자입니다. 나는 이것을 테스트하지 않았지만 작동해야합니다.

감사!

나는 당신의 첫 번째 접근 방식이 더 명확하고 읽을 수 있다고 말할 것입니다. 두 번째 방법은 반사 냄새가 나고, 안전하지 않으며 이상하게 보입니다. 그만큼 ManagementObject 여러 가지를 나타낼 수 있으므로 분명하지 않습니다. .InvokeMethod("Delete") 실제로 디렉토리를 삭제합니다.

첫 번째 접근법 (directory.delete)에 대해 내가 싫어하는 것은 읽기 전용 파일을 포함하는 하위 디렉터가 있으며 읽기 전용 파일도있는 하위 디렉토리가있는 경우입니다. 디렉토리의 모든 파일과 모든 하위 디렉토리에 대해 재귀 적으로 해당 플래그를 끄는 것 같습니다.

두 번째 접근 방식을 사용하면 첫 번째 디렉토리 만 삭제할 수 있으며 파일이 읽기 전용인지 확인하지 않습니다. 그러나 C#에서 WMI를 사용한 것은 이번이 처음이므로 그다지 편안하지는 않습니다. 따라서 System.IO 메소드를 사용하는 대신 다른 응용 프로그램에 대한 WMI 접근 방식을 언제 사용할 것인지 확신 할 수 없습니다.

표면적으로 WMI 접근법을 사용하는 것은 전체 파일 시스템을 반복하는 것보다 더 효율적으로 보입니다 (예 : 디렉토리에 수천 개의 파일이 10 개 있다고 가정 함). 그러나 WMI도 반복을 수행하지 않는다는 것을 모릅니다. 그렇다면 금속에 더 가깝게 (다시 가정) 더 효율적이어야합니다.

우아함을 위해, 나는 재귀 방법이 시원하다는 것을 인정합니다.

성능 테스트는 효율성 질문에 답해야합니다. 그리고 디렉토리 인포의 확장 방법으로 싸면 우아 할 수 있습니다.

다음은 재귀를 피하는 또 다른 솔루션입니다.

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# 길이 긴 폴더 삭제

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();
  }
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top