Directory.Delete (path, true)를 사용하여 디렉토리를 삭제할 수 없습니다.


383

.NET 3.5를 사용하고 있는데 다음을 사용하여 디렉토리를 반복적으로 삭제하려고합니다.

Directory.Delete(myPath, true);

파일을 사용 중이거나 권한 문제가있는 경우이를 throw해야하지만 그렇지 않으면 디렉토리와 모든 내용을 삭제해야합니다.

그러나 때때로 나는 이것을 얻는다 :

System.IO.IOException: The directory is not empty.
    at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
    at System.IO.Directory.DeleteHelper(String fullPath, String userPath, Boolean recursive)
    at System.IO.Directory.Delete(String fullPath, String userPath, Boolean recursive)
    ...

이 방법이 때때로 발생한다는 사실은 놀랍지 않지만 재귀가 참일 때이 특정 메시지를 얻는 것에 놀랐습니다. ( 디렉토리가 비어 있지 않다는 것을 알고 있습니다.)

AccessViolationException 대신 이것을 볼 이유가 있습니까?


13
AccessViolationException은 표시되지 않습니다. 디스크 액세스가 아닌 잘못된 포인터 작업을위한 것입니다.
Joe White

1
이것은 열린 파일 핸들 또는 무언가와 같이 디렉토리가 비어 있지 않은 것 이외의 일종의 IO 문제 인 것 같습니다. 재귀 삭제 옵션을 사용하고 IOException을 catch하여 열려있는 파일 핸들을 검색하고 닫은 다음 다시 시도하십시오. 여기에 대한 논의가 있습니다 : stackoverflow.com/questions/177146/…
Dan Csharpster

답변:


231

편집자 주 : 이 답변에는 유용한 정보가 포함되어 있지만의 작동 방식에 대해서는 실제로 잘못되었습니다 Directory.Delete. 이 답변에 대한 의견과이 질문에 대한 다른 답변을 읽으십시오.


나는 전에이 문제에 부딪쳤다.

문제의 근본 원인은이 함수가 디렉토리 구조 내에있는 파일을 삭제하지 않는다는 것입니다. 따라서 디렉토리 자체를 제거하기 전에 디렉토리 구조 내의 모든 파일을 삭제 한 다음 모든 디렉토리를 삭제하는 함수를 작성해야합니다. 나는 이것이 두 번째 매개 변수에 위배된다는 것을 알고 있지만 훨씬 안전한 접근 방식입니다. 또한 파일을 삭제하기 직전에 파일에서 읽기 전용 액세스 속성을 제거하려고 할 수 있습니다. 그렇지 않으면 예외가 발생합니다.

이 코드를 프로젝트에 넣으십시오.

public static void DeleteDirectory(string target_dir)
{
    string[] files = Directory.GetFiles(target_dir);
    string[] dirs = Directory.GetDirectories(target_dir);

    foreach (string file in files)
    {
        File.SetAttributes(file, FileAttributes.Normal);
        File.Delete(file);
    }

    foreach (string dir in dirs)
    {
        DeleteDirectory(dir);
    }

    Directory.Delete(target_dir, false);
}

또한 나에게 누군가가 C:\WINDOWS (%WinDir%)또는 에서이 기능을 호출하기를 원하기 때문에 삭제가 허용되는 시스템 영역에 개인적으로 제한을 추가합니다 C:\.


117
이것은 말이되지 않습니다. Directory.Delete (myPath, true)는 디렉토리 구조 내에있는 모든 파일을 삭제하는 과부하입니다. 당신이 잘못되고 싶다면 Ryan S의 대답으로 잘못하십시오.
시그. Tolleranza

35
Directory.Delete ()가 하위 디렉토리 내부의 파일을 삭제하지만 (재귀 = true) 하위 디렉토리 나 파일 중 하나가 읽기 전용 인 경우 "IOException : 디렉토리가 비어 있지 않습니다"가 발생하기 때문에 +1입니다. 따라서이 솔루션은 Directory.Delete ()보다 효과적입니다.
Anthony Brien

17
Directory.Delete(path, true)파일을 삭제하지 않은 진술 이 잘못되었습니다. MSDN msdn.microsoft.com/en-us/library/fxeahc5f.aspx
Konstantin Spirin

20
-1 누군가이 접근법의 타당성이 매우 의심 스럽다는 명확한 표시를 할 수 있습니까? 경우 Directory.Delete(string,bool)에 실패, 뭔가 잠겨 있거나 mispermissioned하고 이러한 문제에 대한 모든 솔루션은 아무도 크기 적합에게이 없습니다. 사람들은 자신의 맥락에서 그 문제를 해결해야하며 문제에 대한 모든 아이디어 (재시도 및 예외 삼키기)와 함께 좋은 결과를 기대하기 위해 모든 문제를 해결해야합니다.
Ruben Bartelink

37
삭제 한 디렉토리에 다른 폴더에 대한 바로 가기 / 기호 링크가있는 경우이 방법에주의하십시오. 예상보다 더 많이 삭제 될 수 있습니다.
Chanakya

182

재귀 적으로 디렉토리를 삭제하려고 시도하고 탐색기에서 a디렉토리 a\b가 열려 b있으면 삭제되지만 a이동하고 볼 때 디렉토리가 비어 있어도 '디렉토리가 비어 있지 않습니다'라는 오류 가 발생합니다. 모든 응용 프로그램 (탐색기 포함)의 현재 디렉토리는 디렉토리에 대한 핸들을 유지합니다 . 당신이 호출 할 때 Directory.Delete(true), 그것은 아래에서 위로 삭제합니다 b다음 a. b탐색기에서이 열려 있으면 탐색기에서 삭제를 감지하고 b디렉토리를 위쪽으로 변경 cd ..하며 열린 핸들을 정리합니다. 파일 시스템이 비동기 적으로 작동하기 때문에 Directory.Delete탐색기와의 충돌로 인해 작업이 실패합니다.

불완전한 솔루션

필자는 탐색기 스레드가 디렉토리 핸들을 해제 할 수 있도록 현재 스레드를 중단한다는 아이디어와 함께 다음 솔루션을 게시했습니다.

// incomplete!
try
{
    Directory.Delete(path, true);
}
catch (IOException)
{
    Thread.Sleep(0);
    Directory.Delete(path, true);
}

그러나 열린 디렉토리가 삭제하려는 디렉토리 의 바로 하위 인 경우에만 작동합니다 . 경우 a\b\c\d탐색기에서 열려 있고이에를 사용 a,이 기술은 삭제 한 후 실패 d하고 c.

다소 더 나은 솔루션

이 방법은 하위 디렉토리 중 하나가 탐색기에서 열려 있어도 깊은 디렉토리 구조의 삭제를 처리합니다.

/// <summary>
/// Depth-first recursive delete, with handling for descendant 
/// directories open in Windows Explorer.
/// </summary>
public static void DeleteDirectory(string path)
{
    foreach (string directory in Directory.GetDirectories(path))
    {
        DeleteDirectory(directory);
    }

    try
    {
        Directory.Delete(path, true);
    }
    catch (IOException) 
    {
        Directory.Delete(path, true);
    }
    catch (UnauthorizedAccessException)
    {
        Directory.Delete(path, true);
    }
}

우리 자신의 재발의 추가 작업에도 불구하고, 우리는 여전히UnauthorizedAccessException 길을 따라 발생할 수있는 것을 처리해야 합니다. 첫 번째 삭제 시도가 두 번째, 성공한 시도를위한 길을 닦고 있는지 또는 파일 시스템이 따라 올 수있는 예외를 던지거나 잡는 데서 발생하는 타이밍 지연인지는 확실하지 않습니다.

블록 Thread.Sleep(0)의 시작 부분에 a 를 추가하여 일반적인 조건에서 발생하고 포착되는 예외 수를 줄일 수 있습니다 try. 또한 시스템로드가 많은 경우 두 가지 Directory.Delete시도 를 모두 수행 하여 실패 할 수있는 위험이 있습니다. 이 솔루션을보다 강력한 재귀 삭제의 시작점으로 고려하십시오.

일반적인 답변

이 솔루션은 Windows 탐색기와 상호 작용하는 특성 만 해결합니다. 견고한 삭제 작업을 원할 경우, 무엇이든 (바이러스 스캐너 등) 언제라도 삭제하려는 항목에 대해 열린 핸들을 가질 수 있다는 점을 명심해야합니다. 따라서 나중에 다시 시도해야합니다. 나중에 얼마나 많이 시도하고 몇 번 시도하는지는 개체를 삭제하는 것이 얼마나 중요한지에 달려 있습니다. 으로 MSDN을 나타냅니다 ,

강력한 파일 반복 코드는 파일 시스템의 많은 복잡성을 고려해야합니다.

NTFS 참조 문서에 대한 링크 만 제공되는이 무고한 진술은 머리카락을 돋보이게해야합니다.

( 편집 : 많이.이 답변은 원래 첫 번째, 불완전한 솔루션 만 가지고있었습니다.)


11
Windows 탐색기에서 경로 또는 경로 아래의 폴더 / 파일 중 하나가 열려 있거나 선택된 동안 Directory.Delete (path, true)를 호출하면 IOException이 발생합니다. 위에서 제안한 try / catch없이 Windows 탐색기를 닫고 기존 코드를 다시 실행하면 정상적으로 작동합니다.
David Alpert

1
작동 방식과 이유를 알 수는 없지만 파일 속성을 설정하고 자체 재귀 함수를 작성하는 동안 효과가 없었습니다.
Stilgar

1
@CarlosLiu "탐색기에게 디렉토리 핸들을 해제 할 수있는 기회"를주기 때문에
Dmitry Gonchar

4
시스템에서 탐색기에 "디렉토리 핸들 해제"를 요청한 다음 디렉토리를 삭제하려고합니다. 디렉토리 핸들이 제 시간에 삭제되지 않은 경우 예외가 발생하고 catch블록이 실행됩니다 (그러므로 Explorer는 명령을 보내지 않았으므로 계속 디렉토리를 해제합니다). 블록은 이미 시스템에 약간의 시간을 더 주었 Thread.Sleep(0)으므로 호출 이 필요하거나 필요하지 않을 수 catch있지만 저렴한 비용으로 약간의 추가 안전을 제공합니다. 그 후, Delete디렉토리가 이미 해제 된 상태 에서 가 호출됩니다.
Zachary Kniebel

1
@ PandaWood는 실제로이 Sleep (100) 만 나를 위해 일했습니다. 수면 (0)이 작동하지 않았습니다. 나는 무슨 일이 일어나고 있으며 이것을 올바르게 해결하는 방법을 모른다. 서버로드에 의존하고 나중에 300 또는 400이 있어야한다면 어떻게해야합니까? 그것을 아는 방법. 또 다른 적절한 길이어야합니다 ...
로마

43

계속 진행하기 전에 제어 할 수있는 다음 이유를 확인하십시오.

  • 폴더가 프로세스의 현재 디렉토리로 설정되어 있습니까? 그렇다면 먼저 다른 것으로 변경하십시오.
  • 해당 폴더에서 파일을 열거 나 DLL을로드 했습니까? (닫거나 언로드하는 것을 잊었습니다)

그렇지 않으면 통제 할 수없는 다음의 정당한 이유를 확인하십시오.

  • 해당 폴더에 읽기 전용으로 표시된 파일이 있습니다.
  • 해당 파일 중 일부에 대한 삭제 권한이 없습니다.
  • 파일 또는 하위 폴더가 탐색기 또는 다른 앱에서 열려 있습니다.

위의 문제 중 하나라도 문제가되면 삭제 코드를 개선하기 전에 문제가 발생하는 이유를 이해해야합니다. 앱이 읽기 전용 또는 액세스 할 수없는 파일을 삭제 해야합니까 ? 누가 그런 식으로 표시했고 왜 그런가요?

위의 이유를 배제한 후에도 여전히 가짜 실패의 가능성이 있습니다. 누군가 삭제중인 파일 또는 폴더에 대한 핸들을 보유한 경우 삭제에 실패하며 누군가 폴더를 열거하거나 파일을 읽는 여러 가지 이유가 있습니다.

  • 검색 인덱서
  • 안티 바이러스
  • 백업 소프트웨어

허위 오류를 처리하는 일반적인 방법은 여러 번 시도하여 시도간에 일시 중지하는 것입니다. 당신은 분명히 영원히 계속 노력하고 싶지 않기 때문에 특정 횟수의 시도 후에 포기하고 예외를 던지거나 오류를 무시해야합니다. 이처럼 :

private static void DeleteRecursivelyWithMagicDust(string destinationDir) {
    const int magicDust = 10;
    for (var gnomes = 1; gnomes <= magicDust; gnomes++) {
        try {
            Directory.Delete(destinationDir, true);
        } catch (DirectoryNotFoundException) {
            return;  // good!
        } catch (IOException) { // System.IO.IOException: The directory is not empty
            System.Diagnostics.Debug.WriteLine("Gnomes prevent deletion of {0}! Applying magic dust, attempt #{1}.", destinationDir, gnomes);

            // see http://stackoverflow.com/questions/329355/cannot-delete-directory-with-directory-deletepath-true for more magic
            Thread.Sleep(50);
            continue;
        }
        return;
    }
    // depending on your use case, consider throwing an exception here
}

필자의 의견으로는 가짜 실패가 항상 가능하기 때문에 모든 삭제에 이와 같은 도우미를 사용해야합니다. 그러나이 코드를 맹목적으로 복사하는 것이 아니라 사용 사례에 맞게 수정해야합니다.

% LocalAppData % 아래에있는 내 앱에서 생성 된 내부 데이터 폴더에 대해 잘못된 오류가 발생하여 분석은 다음과 같습니다.

  1. 폴더는 내 응용 프로그램에 의해서만 제어되며 사용자는 해당 폴더 내에서 읽기 전용 또는 액세스 할 수없는 것으로 표시하고 그 이유를 다루지 않을 유효한 이유가 없습니다.

  2. 거기에는 사용자가 만든 귀중한 자료가 없으므로 실수로 무언가를 강제로 삭제할 위험이 없습니다.

  3. 내부 데이터 폴더이기 때문에 탐색기에서 폴더가 열릴 것으로 기대하지 않습니다. 적어도 사건을 구체적으로 처리 할 필요가 없다고 생각합니다 (즉, 지원을 통해 사건을 잘 처리하고 있습니다).

  4. 모든 시도가 실패하면 오류를 무시하기로 선택합니다. 최악의 경우, 앱이 새로운 리소스의 압축을 풀지 못하고 충돌이 발생하여 사용자에게 지원을 요청하라는 메시지를 표시합니다. 지원이 자주 발생하지 않는 한 허용됩니다. 또는 앱이 충돌하지 않으면 오래된 데이터가 남겨져 다시 받아 들일 수 있습니다.

  5. 재 시도를 500ms (50 * 10)로 제한합니다. 이것은 실제로 작동하는 임의의 임계 값입니다. 사용자가 응답을 멈췄다 고 생각하면서 앱을 죽이지 않도록 임계 값을 짧게 만들고 싶었습니다. 반면에, 0.5 초는 범죄자가 내 폴더 처리를 마치는 데 충분한 시간입니다. 때로는 Sleep(0)받아 들일 수있는 것으로 보이는 다른 SO 답변으로 판단 할 때, 한 번의 재시도 이상을 경험하는 사용자는 거의 없습니다.

  6. 나는 50ms마다 다시 시도하는데, 이는 또 다른 임의의 숫자입니다. 파일을 삭제하려고 할 때 파일을 처리 (인덱싱, 검사)하면 50ms가 필자의 경우 처리가 완료 될 것으로 예상되는 시점입니다. 또한 50ms는 눈에 띄게 느려지지 않을 정도로 작습니다. 다시 말하지만, Sleep(0)많은 경우에 충분한 것으로 보이므로 너무 지연하고 싶지 않습니다.

  7. 코드는 모든 IO 예외에서 재 시도합니다. 나는 일반적으로 % LocalAppData %에 액세스하는 예외를 기대하지 않으므로, 단순성을 선택하고 합법적 인 예외가 발생할 경우 500ms 지연의 위험을 감수했습니다. 또한 다시 시도하려는 정확한 예외를 감지하는 방법을 알고 싶지 않았습니다.


7
PPS 몇 달 후,이 코드가 약간 문제가 완전히 해결되었다고보고하게되어 기쁩니다. 이 문제에 대한 지원 요청은 주당 1-2 회에서 0으로 줄었습니다.
Andrey Tarantsov

1
+0이 방법은 더 강력하지만 덜 있습니다. stackoverflow.com/a/7518831/11635 보다 완벽한 솔루션입니다 . 동일한 프로그래밍-우연히 프로그래밍-주의해서 처리하십시오. 코드에 구현 된 유용한 점 중 하나는 재 시도를 수행하려는 경우 마지막 시도 이후 디렉토리가 '사라 졌'는지 여부에 대한 모호함을 염두에 두어야한다는 점 Directory.Exists입니다.
Ruben Bartelink

1
그것을 좋아합니다 ... 내가하는 일을 모르겠습니다. 이것은 항상 저에게 고통의 포인트입니다 ...하지만 탐색기에서 디렉토리를 열었 기 때문이 아닙니다 ... 인터넷에 대해 더 많은 소란이 없습니다. 또는 적은 버그 ... 적어도 나와 Andrey는 처리 방법이 있습니다 :)
TCC

2
@RubenBartelink 좋아, 그래서 우리는 이것에 동의 할 수 있다고 생각합니다 .SO 답변이 많은 초보자에게 장애가 될 것이므로 하나의 특정 앱에서 작동하고 모든 경우에 적합하지 않은 코드를 게시하는 것이 좋습니다. 및 / 또는 무식한 개발자. 나는 그것을 커스터마이즈를위한 시작점으로 주었지만, 어떤 사람들은 그것을 그대로 사용하려고하는데 그것은 나쁜 일입니다.
Andrey Tarantsov

2
@nopara 비교할 필요가 없습니다. 루프에서 벗어나면 실패한 것입니다. 그리고 예, 많은 경우에 예외를 던지고 사용자가 볼 수있는 메시지와 함께 적절한 오류 처리 코드를 스택에 추가하려고합니다.
Andrey Tarantsov

18

현대 비동기 답변

허용되는 대답은 잘못되었습니다. 디스크에서 파일을 가져 오는 데 걸리는 시간이 파일을 잠그는 모든 것을 해제하기 때문에 일부 사람들에게는 효과가있을 수 있습니다. 사실 이것은 다른 프로세스 / 스트림 / 액션에 의해 파일이 잠겨 있기 때문에 발생합니다. 다른 답변은 Thread.Sleep(Yuck)을 사용 하여 얼마 후에 디렉토리 삭제를 다시 시도합니다. 이 질문은 더 현대적인 답변으로 다시 방문해야합니다.

public static async Task<bool> TryDeleteDirectory(
   string directoryPath,
   int maxRetries = 10,
   int millisecondsDelay = 30)
{
    if (directoryPath == null)
        throw new ArgumentNullException(directoryPath);
    if (maxRetries < 1)
        throw new ArgumentOutOfRangeException(nameof(maxRetries));
    if (millisecondsDelay < 1)
        throw new ArgumentOutOfRangeException(nameof(millisecondsDelay));

    for (int i = 0; i < maxRetries; ++i)
    {
        try
        {
            if (Directory.Exists(directoryPath))
            {
                Directory.Delete(directoryPath, true);
            }

            return true;
        }
        catch (IOException)
        {
            await Task.Delay(millisecondsDelay);
        }
        catch (UnauthorizedAccessException)
        {
            await Task.Delay(millisecondsDelay);
        }
    }

    return false;
}

단위 테스트

이 테스트는 잠긴 파일로 인해 Directory.Delete어떻게 실패하고 TryDeleteDirectory위 의 방법으로 문제가 해결 되는지에 대한 예를 보여줍니다 .

[Fact]
public async Task TryDeleteDirectory_FileLocked_DirectoryNotDeletedReturnsFalse()
{
    var directoryPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
    var subDirectoryPath = Path.Combine(Path.GetTempPath(), "SubDirectory");
    var filePath = Path.Combine(directoryPath, "File.txt");

    try
    {
        Directory.CreateDirectory(directoryPath);
        Directory.CreateDirectory(subDirectoryPath);

        using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.Write))
        {
            var result = await TryDeleteDirectory(directoryPath, 3, 30);
            Assert.False(result);
            Assert.True(Directory.Exists(directoryPath));
        }
    }
    finally
    {
        if (Directory.Exists(directoryPath))
        {
            Directory.Delete(directoryPath, true);
        }
    }
}

[Fact]
public async Task TryDeleteDirectory_FileLockedThenReleased_DirectoryDeletedReturnsTrue()
{
    var directoryPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
    var subDirectoryPath = Path.Combine(Path.GetTempPath(), "SubDirectory");
    var filePath = Path.Combine(directoryPath, "File.txt");

    try
    {
        Directory.CreateDirectory(directoryPath);
        Directory.CreateDirectory(subDirectoryPath);

        Task<bool> task;
        using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.Write))
        {
            task = TryDeleteDirectory(directoryPath, 3, 30);
            await Task.Delay(30);
            Assert.True(Directory.Exists(directoryPath));
        }

        var result = await task;
        Assert.True(result);
        Assert.False(Directory.Exists(directoryPath));
    }
    finally
    {
        if (Directory.Exists(directoryPath))
        {
            Directory.Delete(directoryPath, true);
        }
    }
}

"현대"의 의미를 확장 할 수 있습니까? 당신의 접근 방식의 장점은 무엇입니까? 당신의 의견으로는 다른 사람들이 왜 틀렸습니까?
TinyRacoon

1
다른 사람들은 틀리지 않습니다. 그들은 단지 나이가 API처럼 사용할 Thread.Sleep오늘과 사용을 피해야하는 async/ awaitTask.Delay대신합니다. 이해할 수 있습니다. 이것은 매우 오래된 질문입니다.
Muhammad Rehan Saeed

이 방법은 인해 (적어도 아닌 문자 그대로 라인을위한 온라인 변환을) VB.Net에서 작동하지 않습니다BC36943 'Await' cannot be used inside a 'Catch' statement, a 'Finally' statement, or a 'SyncLock' statement.
amonroejj

@amonroejj 이전 버전을 사용해야합니다. 그것은 수정되었습니다.
무하마드 Rehan

if (!Directory.Exists(directoryPath)) { return true; } await Task.Delay(millisecondsDelay); 디렉토리가 실제로 사라질 때까지 기다리기 위해 true 를 반환하는 대신에 약간의 개선
fuchs777

16

언급해야 할 중요한 사항 중 하나는 주석으로 추가했지만 허용되지는 않습니다. 오버로드의 동작이 .NET 3.5에서 .NET 4.0으로 변경되었다는 것입니다.

Directory.Delete(myPath, true);

.NET 4.0부터는 3.5 폴더가 아닌 폴더 자체의 파일을 삭제합니다. 이것은 MSDN 설명서에서도 볼 수 있습니다.

.NET 4.0

지정된 디렉토리지정된 경우 디렉토리의 서브 디렉토리 및 파일을 삭제 합니다 .

.NET 3.5

비어있는 디렉토리 와 표시된 경우 디렉토리의 하위 디렉토리 및 파일을 삭제 합니다 .


3
문서 변경 일 뿐이라고 생각합니다. "빈 디렉토리"만 삭제하는 경우 2 ° 매개 변수를 사용하여 디렉토리의 파일도 삭제한다는 것은 무엇입니까? 비어 있으면 파일이 없습니다 ...
Pisu

당신이 틀렸다고 생각합니다. 두 프레임 워크 버전으로 코드를 테스트 한 후 이것을 게시했습니다. 비어 있지 않은 폴더를 3.5에서 삭제하면 예외가 발생합니다.
jettatore

15

델파이에서도 똑같은 문제가있었습니다. 그리고 최종 결과는 내 응용 프로그램이 삭제하려는 디렉토리를 잠그고 있다는 것입니다. 어떻게 든 디렉토리에 쓸 때 디렉토리가 잠겼습니다 (일부 임시 파일).

캐치 22는 삭제하기 전에 부모로 간단한 변경 디렉토리 를 만들었 습니다.


6
+1 이제 디렉토리에 대한 msdn 이 있습니다. 삭제에 언급되어 있습니다!
Ruben Bartelink

3
전체 소스 코드 샘플을 사용하는 최종 솔루션은 무엇입니까?
Kiquenet

11

나는이 간단한 비 재귀 적 방법에 대해 아무도 생각하지 않아 놀랐습니다.이 방법은 각 파일의 읽기 전용 속성을 변경할 필요없이 읽기 전용 파일을 포함하는 디렉토리를 삭제할 수 있습니다.

Process.Start("cmd.exe", "/c " + @"rmdir /s/q C:\Test\TestDirectoryContainingReadOnlyFiles"); 

(인터넷을 통해 사용할 수있는 cmd 창을 일시적으로 실행하지 않도록 비트를 변경하십시오)


우리와 공유하게되어 기쁘지만 cmd 창을 실행하는 것을 막는 데 필요한 약간의 변경 사항을 포함시켜 인터넷을 통해 검색하라는 메시지를 표시하는 것이 친절합니까?
ThunderGr

작동하지 않습니다. 명령 프롬프트 또는 탐색기에서 파일을 삭제할 수있는 것과 동일한 상황에서이 코드를 사용하여 rmdir을 호출하면 종료 디렉토리 145가 표시됩니다.이 디렉토리는 "디렉토리가 비어 있지 않습니다"로 변환됩니다. 디렉토리를 비워 두지 만 Directory.Delete ( "", true)와 동일하게 여전히 위치에 있습니다.
Kevin Coulombe

@Kevin Coulombe, Humm ... / s / q 스위치를 사용하고 있습니까?
유쉬 소니

1
@KevinCoulombe : 예. COM 구성 요소 여야합니다. 일반 오래된 C #을 시도하면 작동하고 내부 파일 (읽기 전용 또는 읽지 않은 전용 파일)과 함께 디렉토리를 삭제합니다.
Piyush Soni 2019

5
프레임 워크에 있어야하는 것에 대해 외부 구성 요소에 의존하기 시작하면 "이상적이지 않은"아이디어 코즈이므로 더 이상 휴대하기가 어렵습니다 (또는 더 어렵습니다). exe가 없으면 어떻게해야합니까? 또는 / option이 변경 되었습니까? Jeremy Edwards의 해결책이 효과적이라면 IMHO가 선호되어야합니다.
frenchone March

11

다음을 실행하여 오류를 재현 할 수 있습니다.

Directory.CreateDirectory(@"C:\Temp\a\b\c\");
Process.Start(@"C:\Temp\a\b\c\");
Thread.Sleep(1000);
Directory.Delete(@"C:\Temp\a\b\c");
Directory.Delete(@"C:\Temp\a\b");
Directory.Delete(@"C:\Temp\a");

'b'디렉토리를 삭제하려고하면 IOException "디렉토리가 비어 있지 않습니다"가 발생합니다. 우리는 디렉토리 'c'를 방금 삭제했기 때문에 어리 석습니다.

내가 이해 한 바에 따르면, 디렉토리 'c'는 삭제 된 것으로 표시됩니다. 그러나 시스템에서 삭제가 아직 커밋되지 않았습니다. 시스템이 작업이 완료되었다고 응답했지만 실제로 처리 중입니다. 시스템은 파일 탐색기가 상위 디렉토리에 집중하여 삭제를 커미트하기를 기다릴 수 있습니다.

삭제 기능 ( http://referencesource.microsoft.com/#mscorlib/system/io/directory.cs ) 의 소스 코드를 보면 기본 Win32Native.RemoveDirectory 기능을 사용하는 것을 볼 수 있습니다. 이 대기하지 않는 동작은 다음과 같습니다.

RemoveDirectory 함수는 디렉토리를 닫을 때 삭제하도록 표시합니다. 따라서 디렉토리에 대한 마지막 핸들이 닫힐 때까지 디렉토리가 제거되지 않습니다.

( http://msdn.microsoft.com/en-us/library/windows/desktop/aa365488(v=vs.85).aspx )

수면 및 재 시도가 해결책입니다. ryascl의 솔루션을 참조하십시오.


8

Explorer 셸에서 그렇게 할 수는 있지만 C : \ Documents and Settings에서 User Profile 디렉토리를 삭제하는 이상한 권한 문제가있었습니다.

File.SetAttributes(target_dir, FileAttributes.Normal);
Directory.Delete(target_dir, false);

디렉토리에서 "파일"작업이 수행하는 작업은 이해가되지 않지만 작동한다는 것은 알고 있습니다.


2
디렉토리에 많은 파일이 있고 Explorer가 해당 파일을 포함하는 폴더를 여는 경우 여전히 희망은 없습니다.
보고

3

이 답변은 https://stackoverflow.com/a/1703799/184528에 근거합니다 . 내 코드와의 차이점은 필요한 경우 Directory 삭제에 대한 많은 호출 하위 디렉토리와 파일 만 재귀한다는 것입니다. 첫 번째 시도에서 디렉토리가 삭제되어 Windows 탐색기로 인해 발생할 수 있습니다.

    public static void DeleteDirectory(string dir, bool secondAttempt = false)
    {
        // If this is a second try, we are going to manually 
        // delete the files and sub-directories. 
        if (secondAttempt)
        {
            // Interrupt the current thread to allow Explorer time to release a directory handle
            Thread.Sleep(0);

            // Delete any files in the directory 
            foreach (var f in Directory.GetFiles(dir, "*.*", SearchOption.TopDirectoryOnly))
                File.Delete(f);

            // Try manually recursing and deleting sub-directories 
            foreach (var d in Directory.GetDirectories(dir))
                DeleteDirectory(d);

            // Now we try to delete the current directory
            Directory.Delete(dir, false);
            return;
        }

        try
        {
            // First attempt: use the standard MSDN approach.
            // This will throw an exception a directory is open in explorer
            Directory.Delete(dir, true);
        }
        catch (IOException)
        {
            // Try again to delete the directory manually recursing. 
            DeleteDirectory(dir, true);
        }
        catch (UnauthorizedAccessException)
        {
            // Try again to delete the directory manually recursing. 
            DeleteDirectory(dir, true);
        } 
    }

그렇다면 어떻게 폴더를 삭제해야 UnauthorizedAccessException합니까? 다시 던질 것입니다. 다시 한번. 그리고 다시 ... 매번 가면서 catch함수를 다시 호출 할 것이기 때문 입니다. A Thread.Sleep(0);는 사용 권한을 변경하지 않습니다. 그 시점에서 오류를 기록하고 정상적으로 실패해야합니다. 그리고이 루프는 (하위) 디렉토리가 열려있는 한 계속 진행되며 프로그래밍 방식으로 닫히지 않습니다. 우리는 그러한 것들이 열려있는 한 그렇게 할 수 있도록 준비되어 있습니까? 더 좋은 방법이 있습니까?
vapcguy

이 생길 경우 UnauthorizedAccessException수동으로 수동으로 각 파일을 삭제하려고합니다. 따라서 디렉토리 구조로 이동하여 계속 진행합니다. 예, 잠재적으로 모든 파일과 디렉토리에 동일한 예외가 발생하지만 탐색기가 핸들을 잡고 있기 때문에 간단하게 발생할 수 있습니다 ( stackoverflow.com/a/1703799/184528 참조 ) "tryAgain"을 "secondTry"로 변경합니다. 더 명확하게.
cdiggins 2012 년

더 간결하게 대답하기 위해 "true"를 전달하고 다른 코드 경로를 실행합니다.
cdiggins 2012 년

맞아, 편집 내용을 보았지만 요점은 파일 삭제가 아니라 디렉토리 삭제와 관련이 있습니다. 필자는 Process.Kill()파일이 잠길 수있는 모든 프로세스에서 기본적 으로 수행 할 수있는 코드를 작성 하고 파일을 삭제했습니다. 내가 겪는 문제는 해당 파일 중 하나가 여전히 열려있는 디렉토리를 삭제할 때입니다 ( stackoverflow.com/questions/41841590/… 참조 ). 따라서이 루프를 다시 수행하면 다른 작업을 수행하더라도 Directory.Delete()해당 폴더에서 다시 수행하면 해당 핸들을 해제 할 수 없으면 여전히 실패합니다.
vapcguy

그리고 UnauthorizedAccessException파일을 삭제 한 이후에도 동일하게 발생 합니다 (이 코드에 도달했기 때문에 허용되었다고 가정해도 실패했습니다 Directory.Delete())는 마 법적으로 디렉토리를 삭제할 권한을 부여하지 않습니다.
vapcguy

3

위의 솔루션 중 어느 것도 나를 위해 잘 작동하지 않았습니다. 나는 다음과 같이 @ryascl 솔루션의 편집 버전을 사용하여 끝났습니다.

    /// <summary>
    /// Depth-first recursive delete, with handling for descendant 
    /// directories open in Windows Explorer.
    /// </summary>
    public static void DeleteDirectory(string path)
    {
        foreach (string directory in Directory.GetDirectories(path))
        {
            Thread.Sleep(1);
            DeleteDir(directory);
        }
        DeleteDir(path);
    }

    private static void DeleteDir(string dir)
    {
        try
        {
            Thread.Sleep(1);
            Directory.Delete(dir, true);
        }
        catch (IOException)
        {
            DeleteDir(dir);
        }
        catch (UnauthorizedAccessException)
        {
            DeleteDir(dir);
        }
    }

2

다른 스레드 또는 프로세스가 디렉토리에 파일을 추가하는 경쟁 조건이있을 수 있습니까?

순서는 다음과 같습니다.

삭제 프로세스 A :

  1. 디렉토리 비우기
  2. (현재 비어있는) 디렉토리를 삭제하십시오.

다른 사람이 1과 2 사이에 파일을 추가하면 2가 예외를 throw합니까?


2

이 문제와 디렉토리 삭제와 관련된 다른 예외를 해결하는 데 몇 시간을 보냈습니다. 이것은 나의 해결책이다

 public static void DeleteDirectory(string target_dir)
    {
        DeleteDirectoryFiles(target_dir);
        while (Directory.Exists(target_dir))
        {
            lock (_lock)
            {
                DeleteDirectoryDirs(target_dir);
            }
        }
    }

    private static void DeleteDirectoryDirs(string target_dir)
    {
        System.Threading.Thread.Sleep(100);

        if (Directory.Exists(target_dir))
        {

            string[] dirs = Directory.GetDirectories(target_dir);

            if (dirs.Length == 0)
                Directory.Delete(target_dir, false);
            else
                foreach (string dir in dirs)
                    DeleteDirectoryDirs(dir);
        }
    }

    private static void DeleteDirectoryFiles(string target_dir)
    {
        string[] files = Directory.GetFiles(target_dir);
        string[] dirs = Directory.GetDirectories(target_dir);

        foreach (string file in files)
        {
            File.SetAttributes(file, FileAttributes.Normal);
            File.Delete(file);
        }

        foreach (string dir in dirs)
        {
            DeleteDirectoryFiles(dir);
        }
    }

이 코드는 약간의 지연이 있으므로 내 응용 프로그램에는 중요하지 않습니다. 그러나 삭제하려는 디렉토리 내에 많은 서브 디렉토리가있는 경우 지연이 문제가 될 수 있습니다.


8
-1 지연은 무엇입니까? 우연의 일치로 프로그래밍하지 마십시오!
Ruben Bartelink

1
@Ruben 나는 당신이 그것에 대해 틀렸다고 말하지 않았습니다. 나는 단지 이것을 위해 그것을 내려주는 것은 가혹한 처벌이라고 말했다. 그러나 귀하에게 동의하지만 4 개의 공감 투표 결과는 4 개의 공감 투표 결과를 얻지 못했습니다. 귀하의 의견도
찬성하지만

1
@RubenBartelink 및 기타 :이 코드가 마음에 들지 않지만 (유사한 방법으로 다른 솔루션을 게시했습니다) 지연이 합리적입니다. 이 문제는 앱이 통제 할 수없는 것 같습니다. 다른 앱이 FS를 주기적으로 다시 검색하여 폴더를 잠깐 동안 잠급니다. 지연은 문제를 해결하여 버그 보고서 카운트를 0으로 줄입니다. 근본 원인에 대해 어리석은 생각이없는 사람은 누구입니까?
Andrey Tarantsov

1
@RubenBartelink 사실, 생각할 때 NTFS 디렉토리 삭제 중에 지연 및 재시도 방식을 사용 하지 않는 것은 무의미한 해결책입니다. 진행중인 모든 파일 탐색은 삭제를 차단하므로 조만간 실패 할 수밖에 없습니다. 또한 모든 타사 검색, 백업, 바이러스 백신 및 파일 관리 도구가 폴더 외부에있을 것으로 예상 할 수 없습니다.
Andrey Tarantsov

1
@RubenBartelink 또 다른 예를 들어, 100ms의 지연 시간을 제공한다고 가정하면 대상 PC의 모든 소프트웨어에서 가장 높은 잠금 시간은 AV 소프트웨어 = 90ms입니다. 또한 70ms 동안 파일을 잠그는 백업 소프트웨어가 있다고 가정하십시오. 이제 AV는 파일을 잠그고 앱은 100ms를 기다립니다. 일반적으로 괜찮지 만 백업 소프트웨어는 AV 스캔의 70ms 마크에서 파일을 가져 오기 시작하므로 다른 잠금이 발생하므로 파일을 해제하는 데 40ms가 더 걸립니다. 따라서 AV 소프트웨어는 더 오래 걸리고 100ms는 일반적으로 두 앱 중 하나보다 길지만 중간에 시작하는 시점을 고려해야합니다.
vapcguy

2

파일을 삭제하지 않는 재귀 디렉토리 삭제는 예상치 못한 결과입니다. 그에 대한 내 수정 :

public class IOUtils
{
    public static void DeleteDirectory(string directory)
    {
        Directory.GetFiles(directory, "*", SearchOption.AllDirectories).ForEach(File.Delete);
        Directory.Delete(directory, true);
    }
}

이것이 도움이되었지만 일반적으로 Directory.Delete 는 msdn에 설명 된 것처럼 재귀 적 삭제시 디렉토리 내부의 파일을 삭제하는 경우를 경험 했습니다. .

때때로 나는 Windows 탐색기의 사용자 로서이 불규칙한 행동을 경험합니다 : 때로는 폴더를 삭제할 수 없습니다 (무의미한 메시지는 "액세스 거부"로 생각됩니다). 항목도. 따라서 위의 코드는 기본 클래스 라이브러리 문제가 아닌 OS 이상을 처리한다고 생각합니다.


1

디렉토리 또는 파일이 잠겨있어서 삭제할 수 없습니다. 잠그는 범인을 찾아 제거 할 수 있는지 확인하십시오.


T1000에서 사용자에게 폴더 열기 : "종료되었습니다!"
vapcguy

1

Windows 탐색기에서 경로 또는 하위 폴더를 선택하면 Directory.Delete (path, true)의 단일 실행이 차단되어 위에서 설명한대로 IOException이 발생하고 Windows 탐색기를 상위 폴더로 부팅하고 다음과 같이 진행하는 대신 죽어가는 것으로 보입니다 예상했다.


이것은 내 문제인 것 같습니다. 탐색기를 닫고 다시 실행하자마자 예외는 없습니다. 부모의 부모를 선택하는 것만으로는 충분하지 않았습니다. 실제로 탐색기를 닫아야했습니다.
Scott Marlowe

예, 이런 일이 발생하며 원인이됩니다. 프로그래밍 방식으로 처리하는 방법에 대한 아이디어가 있습니까? 아니면 1000 명의 모든 사용자가 해당 폴더를 닫았는지 항상 대답하는 것입니까?
vapcguy

1

오늘이 문제가있었습니다. 삭제하려는 디렉토리에 Windows 탐색기가 열려 재귀 호출이 실패하여 IOException이 발생했기 때문에 발생했습니다. 디렉토리에 열린 핸들이 없는지 확인하십시오.

또한 MSDN은 사용자가 자신의 recusion을 작성할 필요가 없음을 분명합니다 : http://msdn.microsoft.com/en-us/library/fxeahc5f.aspx


1

TFS2012가있는 빌드 서버에서 Windows Workflow Foundation과 동일한 문제가 발생했습니다. 내부적으로 재귀 플래그가 true로 설정된 워크 플로는 Directory.Delete ()입니다. 우리의 경우 네트워크와 관련된 것으로 보입니다.

네트워크 공유에서 이진 드롭 폴더를 삭제하고 최신 이진 파일로 다시 채우고 다시 채웠습니다. 다른 모든 빌드는 실패합니다. 실패한 빌드 후 드롭 폴더를 열면 폴더가 비어 있습니다. 이는 실제로 디렉토리를 삭제하는 것을 제외하고 Directory.Delete () 호출의 모든 측면이 성공했음을 나타냅니다.

네트워크 파일 통신의 비동기 특성으로 인해 문제가 발생한 것으로 보입니다. 빌드 서버는 파일 서버에 모든 파일을 삭제하도록 지시했으며 파일 서버는 파일이 완전히 완료되지 않았더라도 파일이 있다고보고했습니다. 그런 다음 빌드 서버는 디렉토리 삭제를 요청했으며 파일 서버는 파일 삭제가 완전히 완료되지 않아 요청을 거부했습니다.

우리의 경우 두 가지 가능한 솔루션 :

  • 각 단계 사이의 지연 및 검증을 통해 자체 코드에서 재귀 삭제를 빌드하십시오.
  • IOException 후 X 번까지 다시 시도하여 다시 시도하기 전에 지연

후자의 방법은 빠르고 더럽지 만 트릭을 수행하는 것 같습니다.


1

FileChangesNotifications 때문입니다 .

ASP.NET 2.0 이후에 발생합니다. 앱에서 일부 폴더를 삭제 하면 다시 시작 됩니다. ASP.NET 상태 모니터링을 사용하여 직접 볼 수 있습니다 .

이 코드를 web.config / configuration / system.web에 추가하십시오.

<healthMonitoring enabled="true">
  <rules>
    <add name="MyAppLogEvents" eventName="Application Lifetime Events" provider="EventLogProvider" profile="Critical"/>
  </rules>
</healthMonitoring>


그 후 체크 아웃하십시오 Windows Log -> Application. 무슨 일이야 :

폴더를 삭제할 때 하위 폴더가 있으면 Delete(path, true)먼저 하위 폴더를 삭제합니다. FileChangesMonitor가 앱 제거 및 종료에 대해 알고 있으면 충분합니다. 한편 기본 디렉토리는 아직 삭제되지 않았습니다. 이것은 Log의 이벤트입니다.


여기에 이미지 설명을 입력하십시오


Delete() 작업이 완료되지 않고 앱이 종료되어 예외가 발생합니다.

여기에 이미지 설명을 입력하십시오

이 때 하위 폴더가없는 당신이 삭제되는 폴더에, 단지 모든 파일과 폴더가, 응용 프로그램도 다시 시작지고 삭제 () 삭제,하지만 당신은 예외를하지 않는 응용 프로그램을 다시 시작 인터럽트 아무것도하지 않습니다 때문이다. 그러나 여전히 모든 프로세스 내 세션이 손실되고 다시 시작할 때 앱이 요청에 응답하지 않습니다.

지금 무엇?

이 동작, 디렉토리 접합 , 레지스트리로 FCN 끄기 , 리플렉션을 사용하여 FileChangesMonitor 중지 (노출 된 방법이 없기 때문에) 를 사용하지 않도록 설정하는 몇 가지 해결 방법과 조정이 있지만 FCN이 이유. 데이터 구조 가 아닌 앱 구조를 찾고 있습니다 . 짧은 대답은 앱 외부에 삭제하려는 폴더를 배치하는 것입니다. FileChangesMonitor는 알림을받지 않으며 매번 앱이 다시 시작되지 않습니다. 예외는 없습니다. 웹에서 볼 수있게하려면 다음 두 가지 방법이 있습니다.

  1. 수신 전화를 처리 한 다음 앱 외부 폴더 (wwwroot 외부)를 읽어 파일을 다시 서비스하는 컨트롤러를 만듭니다.

  2. 프로젝트가 크고 성능이 가장 중요한 경우 정적 컨텐츠를 제공하기 위해 작고 빠른 웹 서버를 별도로 설정하십시오. 따라서 IIS에 특정 작업을 맡기게됩니다. 동일한 시스템 (Windows의 경우 mongoose) 또는 다른 시스템 (Linux의 경우 nginx)에있을 수 있습니다. 좋은 소식은 리눅스에서 정적 컨텐츠 서버를 설정하기 위해 추가 Microsoft 라이센스를 지불 할 필요가 없다는 것입니다.

도움이 되었기를 바랍니다.


1

위에서 언급했듯이 "허용 된"솔루션은 재분석 지점에서 실패하지만 사람들은 여전히 ​​그것을 마크 업 (???)합니다. 기능을 올바르게 복제하는 훨씬 짧은 솔루션이 있습니다.

public static void rmdir(string target, bool recursive)
{
    string tfilename = Path.GetDirectoryName(target) +
        (target.Contains(Path.DirectorySeparatorChar.ToString()) ? Path.DirectorySeparatorChar.ToString() : string.Empty) +
        Path.GetRandomFileName();
    Directory.Move(target, tfilename);
    Directory.Delete(tfilename, recursive);
}

나는 나중에 언급 된 권한 사례를 처리하지 않지만 모든 의도와 목적을 위해 FAR BETTER는 원본 / 주식 Directory.Delete () 의 예상 기능 을 제공하며 코드도 훨씬 적습니다 .

'파일 시스템이 여전히 따라 잡기 때문에'(또는 MS가 깨진 기능을 제공 한 이유는 무엇이든) 이전 디렉토리가 방해가되기 때문에 안전하게 처리를 계속할 수 있습니다 .

이점으로, 대상 디렉토리가 크거나 깊으며 대기하지 않으려면 (또는 예외로 귀찮게) 마지막 행을 다음으로 바꿀 수 있습니다.

    ThreadPool.QueueUserWorkItem((o) => { Directory.Delete(tfilename, recursive); });

당신은 여전히 ​​일하는 것이 안전합니다.


2
다음과 같이 할당을 단순화 할 수 있습니다. string tfilename = Path.Combine (Path.GetDirectoryName (target), Path.GetRandomFileName ());
Pete

1
피트에 동의해야합니다. 작성된 코드는 구분 기호를 추가하지 않습니다. 그것은 나의 길을 \\server\C$\dir걸었고 그것을 만들었다 \\server\C$asf.yuw. 그 결과 난에 오류가있어 Directory.Move()- Source and destination path must have identical roots. Move will not work across volumes. 잠긴 파일 또는 오픈가에 도달하지 디렉토리-있도록이있는 경우에 나는 둘 다 핸들을 제외하고 피트의 코드를 사용하면 일을 잘 ThreadPool명령을 사용합니다.
vapcguy

주의 :이 답변은 재귀 = true로만 사용해야합니다. false 인 경우 디렉토리가 비어 있지 않아도 디렉토리를 이동합니다. 어느 것이 버그일까요? 이 경우 올바른 동작은 예외를 발생시키고 디렉토리를 그대로 둡니다.
ToolmakerSteve

1

이 문제는 경로 길이가 260 개보다 큰 디렉토리 (또는 서브 디렉토리)에 파일이있는 경우 Windows에 나타날 수 있습니다.

이러한 경우 \\\\?\C:\mydir대신에 삭제해야합니다 C:\mydir. 260 기호 제한에 대해서는 여기에서 읽을 수 있습니다 .


1

나는이 천년 기술로 해결했습니다 (스레드에서 수면을 그대로 둘 수 있습니다)

bool deleted = false;
        do
        {
            try
            {
                Directory.Delete(rutaFinal, true);                    
                deleted = true;
            }
            catch (Exception e)
            {
                string mensaje = e.Message;
                if( mensaje == "The directory is not empty.")
                Thread.Sleep(50);
            }
        } while (deleted == false);

0

응용 프로그램 (또는 다른 응용 프로그램)의 현재 디렉토리가 삭제하려는 디렉토리 인 경우, 액세스 위반 오류는 아니지만 디렉토리는 비어 있지 않습니다. 현재 디렉토리를 변경하여 자신의 응용 프로그램이 아닌지 확인하십시오. 또한 다른 프로그램 (예 : Word, excel, Total Commander 등)에서 디렉토리가 열려 있지 않은지 확인하십시오. 대부분의 프로그램은 마지막으로 열린 파일의 디렉토리로 이동하여 그 원인이됩니다.


0

네트워크 파일의 경우 Directory.DeleteHelper (recursive : = true)로 인해 파일 삭제 지연으로 인해 IOException이 발생할 수 있습니다.


0

알지 못하는 일부 스트림에 의해 열린 파일이 있다고 생각합니다. 동일한 문제가 있었고 디렉토리를 가리키는 곳에서 삭제하려는 모든 스트림을 닫아서 해결했습니다.


0

이 오류는 파일 또는 디렉토리가 사용중인 것으로 간주되는 경우 발생합니다. 오해의 소지가 있습니다. 탐색기 창 또는 명령 행 창이 트리의 디렉토리 또는 해당 트리의 파일을 사용하는 프로그램에 열려 있는지 확인하십시오.


0

메소드가 비동기적이고 다음과 같이 코딩 될 때 언급 된 문제의 가능한 인스턴스를 해결했습니다.

// delete any existing update content folder for this update
if (await fileHelper.DirectoryExistsAsync(currentUpdateFolderPath))
       await fileHelper.DeleteDirectoryAsync(currentUpdateFolderPath);

이것으로 :

bool exists = false;                
if (await fileHelper.DirectoryExistsAsync(currentUpdateFolderPath))
    exists = true;

// delete any existing update content folder for this update
if (exists)
    await fileHelper.DeleteDirectoryAsync(currentUpdateFolderPath);

결론? Microsoft가 말할 수 없었던 존재를 확인하는 데 사용되는 핸들을 제거하는 비동기 측면이 있습니다. 마치 if 문 내부의 비동기 메서드에 if 문이 using 문처럼 작동하는 것처럼 보입니다.


0

추가 폴더 안에있는 파일을 재귀 또는 삭제하기위한 추가 방법을 만들 필요가 없습니다. 이 모든 것은 전화로 자동 수행

DirectoryInfo.Delete ();

자세한 내용은 여기 입니다.

이와 같은 것이 꽤 잘 작동합니다.

  var directoryInfo = new DirectoryInfo("My directory path");
    // Delete all files from app data directory.

    foreach (var subDirectory in directoryInfo.GetDirectories())
    {
          subDirectory.Delete(true);// true set recursive paramter, when it is true delete sub file and sub folder with files too
    }

메서드를 삭제하는 변수로 true를 전달 하면 파일이있는 하위 파일과 하위 폴더도 삭제됩니다.


-2

위의 답변 중 어느 것도 나를 위해 일하지 않았습니다. 내 자신의 앱 사용이DirectoryInfo대상 디렉토리에서 하여 잠긴 상태로 유지 된 .

가비지 수집을 강제 실행하면 문제가 해결 된 것으로 보이나 즉시 해결되지는 않습니다. 필요한 경우 몇 차례 삭제를 시도합니다.

노트 Directory.Exists는 예외 후에 사라질 수있다. 삭제가 지연된 이유를 모르겠습니다 (Windows 7 SP1).

        for (int attempts = 0; attempts < 10; attempts++)
        {
            try
            {
                if (Directory.Exists(folder))
                {
                    Directory.Delete(folder, true);
                }
                return;
            }
            catch (IOException e)
            {
                GC.Collect();
                Thread.Sleep(1000);
            }
        }

        throw new Exception("Failed to remove folder.");

1
-1 우연의 일치 프로그래밍. GC 할 때 어떤 개체를 수행합니까? 이것은 일반적인 조언이 될까요? (문제가 있다고 생각하고이 코드를 사용했다고 생각하고 지금은 문제가 없다고 생각하지만 그게 요점이 아닙니다.)
Ruben Bartelink

@RubenBartelink 동의합니다. 해킹입니다. 해결 방법이나 방법이 확실하지 않은 경우 무언가를 수행하는 부두 코드. 적절한 해결책을 원합니다.
Reactgular

1
내 문제는 그것이 stackoverflow.com/a/14933880/11635 이상으로 추가되는 것은 매우 투기 적이라는 것 입니다. 가능하다면 중복에 대해 -1을, 우연으로 추측 / 프로그래밍에 -1을 줄 것입니다. 뿌리 GC.Collect는 것은 a) 단지 나쁜 조언이며 b) 잠긴 dirs가 여기에 포함시킬만한 일반적인 일반적인 원인이 아닙니다. 그냥 다른 사람 중 하나를 선택하고 무고한 독자의 마음에 더 혼란을 뿌리지 마십시오
Ruben Bartelink

3
GC.WaitForPendingFinalizers ()를 사용하십시오. GC.Collect () 이후; 예상대로 작동합니다.
Heiner

확실하지 않고, 테스트되지 않았지만, 아마도 using진술로 무언가를하는 것이 더 낫습니다 . using (DirectoryInfo di = new DirectoryInfo(@"c:\MyDir")) { for (int attempts = 0; attempts < 10; attempts++) { try { if (di.Exists(folder)) { Directory.Delete(folder, true); } return; } catch (IOException e) { Thread.Sleep(1000); } } }
vapcguy

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.