디렉터리가 있는 디렉터리를 삭제할 수 없습니다.삭제(경로, 참)
사용하고 있습니다.NET 3.5, 다음을 사용하여 디렉터리를 재귀적으로 삭제하려고 시도:
Directory.Delete(myPath, true);
파일이 사용 중이거나 권한 문제가 있는 경우에는 삭제해야 하지만 그렇지 않은 경우에는 디렉터리와 모든 내용을 삭제해야 합니다.
하지만 가끔 이런 말을 듣곤 합니다.
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)
...
메소드가 가끔 던져지는 것은 놀라운 일이 아니지만, 재귀적인 것이 사실일 때 이 특정 메시지를 받게 되어 놀랐습니다.(디렉토리가 비어 있지 않은 것으로 알고 있습니다.)
액세스 위반 대신 이 메시지가 표시될 이유가 있습니까?예외?
편집자 참고 사항:이 답변에는 유용한 정보가 포함되어 있지만, 실제로는 다음의 작동 방식에 대해 올바르지 않습니다.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:\.
디렉터리를 에는 다음과 같이 .a 디렉토리 " 디토리및"a\b탐색기에서 열려 있습니다.b되지만 'empty'라는합니다.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) try추가적으로, 시스템 부하가 높을 때, 당신은 두 가지를 모두 통과할 수 있는 위험이 위험이 있습니다.Directory.Delete삭제의 합니다.이 솔루션을 보다 강력한 재귀 삭제의 시작점으로 간주합니다.
일반답변
이 솔루션은 Windows 탐색기와 상호 작용하는 특성만 해결합니다.완전 삭제 작업을 수행하려면 바이러스 스캐너 등 모든 항목에 언제든지 삭제하려는 내용에 대한 핸들이 열려 있을 수 있습니다.그래서 당신은 나중에 다시 시도해야 합니다.개체를 삭제하는 것이 얼마나 중요한지에 따라 나중에 시도하는 횟수와 시도 횟수가 달라집니다.MSDN에서 알 수 있듯이,
강력한 파일 반복 코드는 파일 시스템의 많은 복잡성을 고려해야 합니다.
NTFS 참조 문서에 대한 링크만 제공되는 이 무고한 진술은 당신의 머리를 곤두세워야 합니다.
(편집: 많이.이 답변에는 원래 첫 번째 불완전한 솔루션만 포함되어 있었습니다.)
계속 진행하기 전에 다음과 같은 이유가 사용자의 통제 하에 있는지 확인하십시오.
- 폴더가 프로세스의 현재 디렉터리로 설정되어 있습니까?가능한 경우 먼저 다른 항목으로 변경합니다.
- 해당 폴더에서 파일을 열었습니까(또는 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% 아래에 있는 앱에서 생성한 내부 데이터 폴더에 대해 가상 오류가 발생했습니다. 따라서 분석 결과는 다음과 같습니다.
폴더는 내 응용 프로그램에 의해서만 제어되고 사용자는 해당 폴더 안에 있는 내용을 읽기 전용 또는 액세스 불가능으로 표시해야 하는 타당한 이유가 없으므로, 저는 이 경우를 처리하려고 하지 않습니다.
사용자가 만든 귀중한 내용이 없으므로 실수로 강제로 삭제할 위험이 없습니다.
내부 데이터 폴더이기 때문에 탐색기에서 해당 폴더가 열리지 않을 것으로 예상합니다. 적어도 사례를 구체적으로 처리할 필요성은 느끼지 않습니다(즉, 지원을 통해 해당 사례를 잘 처리하고 있습니다).
모든 시도가 실패하면 오류를 무시합니다.최악의 경우, 앱이 일부 새로운 리소스의 압축을 풀지 못하고 중단되고 사용자에게 지원팀에 문의하라는 메시지를 표시합니다. 이는 자주 발생하지 않는 한 허용됩니다.또는 앱이 충돌하지 않으면 오래된 데이터를 남겨둘 것이며, 이는 저에게 다시 허용됩니다.
재시도 횟수를 500ms(50 * 10)로 제한합니다.이것은 실제로 작동하는 임의의 임계값입니다. 저는 사용자가 앱을 죽이지 않도록 충분히 짧은 임계값을 원했습니다. 앱이 응답을 멈췄다고 생각했기 때문입니다.반면에, 공격자가 내 폴더 처리를 완료하는 데는 0.5초의 시간이 충분합니다.때때로 짝수를 발견하는 다른 SO 답변으로 판단합니다.
Sleep(0)한 번 이상의 재시도를 경험하는 사용자는 거의 없습니다.저는 50ms마다 다시 시도하는데, 이것은 또 다른 임의의 숫자입니다.파일을 삭제하려고 할 때 파일이 처리(인덱스, 체크)되고 있다면 제 경우 50ms가 처리 완료를 기대하기에 적절한 시기라고 생각합니다.눈에 속도 저하를 하지 않을 . 다시 "50ms"라는 이름의 파일이 있습니다. 다시 말하지만,
Sleep(0)많은 경우 충분할 것 같으니, 우리는 너무 지연시키고 싶지 않습니다.이 코드는 IO 예외에 대해 다시 시도합니다.일반적으로 %LocalAppData%에 액세스하는 경우 예외가 발생하지 않을 것으로 예상되므로 단순성을 선택하고 합법적인 예외가 발생할 경우 500ms 지연의 위험을 감수했습니다.또한 다시 시도하고 싶은 정확한 예외를 탐지하는 방법을 찾고 싶지 않았습니다.
현대 비동기식 답변
디스크에서 파일을 가져오는 데 걸리는 시간이 파일을 잠그는 데 필요한 모든 시간을 확보하기 때문에 일부 사람들에게 효과가 있을 수 있습니다.이는 파일이 다른 프로세스/스트림/액션에 의해 잠겨 있기 때문입니다.은 다른답다같음다습니과은변다같니습▁use▁the▁other다과를 사용합니다.Thread.Sleep(요크) 일정 시간 후 디렉토리 삭제를 다시 시도합니다.이 질문은 좀 더 현대적인 답변으로 다시 검토할 필요가 있습니다.
public static async Task<bool> TryDeleteDirectory(
string directoryPath,
int maxRetries = 10,
int millisecondsDelay = 30)
{
if (directoryPath == null)
throw new ArgumentNullException(nameof(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);
}
}
}
언급해야 할 한 가지 중요한 사항(댓글로 추가했지만 허용되지 않음)은 오버로드의 동작이 에서 변경되었다는 것입니다.NET 3.5에서 .NET 4.0.
Directory.Delete(myPath, true);
부터 시작합니다.NET 4.0 폴더 자체의 파일을 삭제하지만 3.5에서는 삭제하지 않습니다.이는 MSDN 설명서에서도 확인할 수 있습니다.
.NET 4.0
지정한 디렉터리와 디렉터리에 있는 모든 하위 디렉터리 및 파일(표시된 경우)을 삭제합니다.
.NET 3.5
빈 디렉터리와 디렉터리에 있는 모든 하위 디렉터리 및 파일(표시된 경우)을 삭제합니다.
저도 델파이 밑에서 똑같은 문제를 겪었습니다.결국 제 애플리케이션이 제가 삭제하고자 하는 디렉터리를 잠그고 있었습니다.디렉터리에 쓸 때 디렉터리가 잠겼습니다(일부 임시 파일).
22번 문제는 삭제하기 전에 부모님께 간단한 변경 디렉토리를 작성했다는 것입니다.
다음을 실행하여 오류를 재현할 수 있습니다.
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'를 삭제하려고 하면 IO 예외 "디렉토리가 비어 있지 않습니다"가 발생합니다.방금 디렉터리 'c'를 삭제했으니 바보 같은 소리입니다.
제가 알기로는 디렉토리 'c'가 삭제된 것으로 표시되어 있습니다.그러나 시스템에서 아직 삭제가 수행되지 않았습니다.시스템에서 작업이 완료되었다고 응답하는 메시지가 표시되지만, 실제로는 아직 처리 중입니다.시스템은 파일 탐색기가 삭제를 커밋하기 위해 상위 디렉토리에 초점을 두고 있을 때까지 기다립니다.
삭제 기능의 소스 코드(http://referencesource.microsoft.com/ #mscorlib/system/io/directory.cs )를 보면 네이티브 Win32Native를 사용하는 것을 알 수 있습니다.디렉터리 기능을 제거합니다.이 대기 안 함 동작은 다음과 같습니다.
RemoveDirectory 함수는 디렉토리를 닫을 때 삭제하도록 표시합니다.따라서 디렉토리의 마지막 핸들이 닫힐 때까지 디렉토리는 제거되지 않습니다.
(http://msdn.microsoft.com/en-us/library/windows/desktop/aa365488(v=vs.85).aspx)
수면 후 재시도가 해결책입니다.Cf ryascl의 용액.
각 파일의 읽기 전용 속성을 변경할 필요 없이 읽기 전용 파일이 포함된 디렉터리를 삭제할 수 있는 이 간단한 비재귀적 방법을 아무도 생각하지 않았다는 것이 놀랍습니다.
Process.Start("cmd.exe", "/c " + @"rmdir /s/q C:\Test\TestDirectoryContainingReadOnlyFiles");
(인터넷 전체에서 사용 가능한 cmd 창을 일시적으로 실행하지 않으려면 조금 변경합니다.)
탐색기 셸에서 삭제할 수 없음에도 불구하고 사용자 프로파일 디렉토리(C:\Documents and Settings)를 삭제하는 동안 이상한 사용 권한 문제가 발생했습니다.
File.SetAttributes(target_dir, FileAttributes.Normal);
Directory.Delete(target_dir, false);
디렉터리에서 "파일" 작업이 수행하는 작업은 의미가 없지만, 작동하고 충분하다는 것을 알고 있습니다!
파일을 삭제하지 않는 재귀 디렉터리 삭제는 확실히 예상치 못한 일입니다.그것에 대한 나의 해결책:
public class IOUtils
{
public static void DeleteDirectory(string directory)
{
Directory.GetFiles(directory, "*", SearchOption.AllDirectories).ForEach(File.Delete);
Directory.Delete(directory, true);
}
}
저는 이것이 도움이 되는 사례를 경험했지만, 일반적으로 디렉토리를 경험했습니다.삭제는 msdn에 문서화된 것처럼 재귀 삭제 시 디렉토리 내의 파일을 삭제합니다.
Windows 탐색기 사용자로서도 가끔 이런 비정상적인 동작을 경험합니다. 폴더를 삭제할 수 없는 경우(비의미적인 메시지는 "액세스 거부"로 간주됨) 하지만 하위 항목을 드릴다운하고 삭제하면 상위 항목도 삭제할 수 있습니다.따라서 위의 코드는 기본 클래스 라이브러리 문제가 아닌 OS 이상 문제를 다루고 있다고 생각합니다.
이 답변은 https://stackoverflow.com/a/1703799/184528 을 기반으로 합니다.내 코드와 다른 점은 디렉터리에 대한 호출이 필요할 때만 많은 하위 디렉터리 및 파일 삭제를 반복한다는 것입니다.첫 번째 시도에서 삭제가 실패합니다(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);
}
}
위의 어떤 해결책도 저에게는 잘 되지 않았습니다.저는 아래와 같이 @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);
}
}
다른 스레드 또는 프로세스가 디렉토리에 파일을 추가하는 경합 조건이 있을 수 있습니까?
순서는 다음과 같습니다.
삭제 프로세스 A:
- 디렉터리 비우기
- (지금은 비어 있음) 디렉토리를 삭제합니다.
만약 다른 사람이 1에서 2 사이의 파일을 추가한다면, 아마도 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);
}
}
이 코드는 약간의 지연이 있기 때문에 제 애플리케이션에 중요하지 않습니다.그러나 삭제할 디렉토리 내에 많은 하위 디렉토리가 있는 경우 지연이 문제가 될 수 있습니다.
재귀성을 위한 추가 메소드를 만들거나 폴더 내부의 파일을 추가로 삭제할 필요가 없습니다.이 모든 작업은 자동으로 호출됩니다.
디렉터리 정보.삭제();
자세한 내용은 여기 있습니다.
이와 같은 것은 상당히 효과적입니다.
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를 삭제할 변수로 전달하면 하위 파일과 파일이 있는 하위 폴더도 삭제됩니다.
디렉터리 또는 디렉터리에 있는 파일이 잠겨 있으므로 삭제할 수 없습니다.그것을 잠근 범인을 찾아 제거할 수 있는지 확인하십시오.
Windows 탐색기에서 경로 또는 하위 폴더를 선택하면 디렉터리의 단일 실행을 차단하기에 충분합니다.삭제(경로, true), 위에서 설명한 대로 IO 예외를 던지고 Windows 탐색기를 상위 폴더로 부팅하고 예상대로 처리하는 대신 사망합니다.
저는 오늘 이 문제를 겪었습니다.삭제를 시도하는 디렉터리에 대한 윈도우 탐색기를 열어 놓았기 때문에 반복적인 호출 실패로 인해 IO 예외가 발생했습니다.디렉토리에 열려 있는 핸들이 없는지 확인합니다.
또한 MSDN은 당신이 당신 자신의 철회문을 쓸 필요가 없다는 것을 분명히 합니다: http://msdn.microsoft.com/en-us/library/fxeahc5f.aspx .
TFS2012를 사용하는 빌드 서버의 Windows Workflow Foundation에서도 동일한 문제가 발생했습니다.내부적으로 워크플로우에서 디렉토리를 호출했습니다.recursive 플래그가 true로 설정된 delete()입니다.우리의 경우에는 네트워크와 관련된 것으로 보입니다.
네트워크 공유에서 바이너리 드롭 폴더를 삭제한 후 다시 만들고 최신 바이너리로 채웠습니다.다른 모든 빌드는 실패합니다.빌드 실패 후 드롭 폴더를 열 때 폴더가 비어 있어 디렉토리의 모든 측면을 나타냅니다.실제 디렉터리를 삭제한 것을 제외하고는 삭제() 호출에 성공했습니다.
이 문제는 네트워크 파일 통신의 비동기성으로 인해 발생한 것으로 보입니다.빌드 서버는 파일 서버에 모든 파일을 삭제하라고 했고 파일 서버는 완료되지 않았음에도 불구하고 삭제했다고 보고했습니다.그런 다음 빌드 서버는 디렉터리 삭제를 요청했고 파일 서버는 파일 삭제를 완료하지 않았기 때문에 요청을 거부했습니다.
이 경우 두 가지 가능한 솔루션:
- 각 단계 사이의 지연 및 확인으로 자체 코드에서 재귀 삭제 기능 구축
- IO 예외 후 최대 X회 재시도, 다시 시도하기 전에 지연 발생
후자의 방법은 빠르고 더럽지만 속임수를 쓰는 것 같습니다.
이는 파일 변경 알림 때문입니다.
그것은 ASP 때부터 발생합니다.NET 2.0.앱 내의 일부 폴더를 삭제하면 다시 시작됩니다.ASP를 사용하여 직접 확인할 수 있습니다.NET 상태 모니터링.
이 코드를 웹.config/config/config/system에 추가하기만 하면 됩니다.웹:
<healthMonitoring enabled="true">
<rules>
<add name="MyAppLogEvents" eventName="Application Lifetime Events" provider="EventLogProvider" profile="Critical"/>
</rules>
</healthMonitoring>
후에 해 보세요.Windows Log -> Application무슨 일이 일어나고 있는 일:
폴더를 삭제할 때 하위 폴더가 있으면Delete(path, true)하위 폴더를 먼저 삭제합니다.File Changes Monitor가 제거에 대해 알고 앱을 종료하기만 하면 됩니다.한편, 당신의 기본 디렉토리는 아직 삭제되지 않았습니다.다음은 로그의 이벤트입니다.

Delete()되고 있기 합니다.

삭제할 폴더에 하위 폴더가 없을 때 삭제()는 모든 파일을 삭제하고 해당 폴더, 앱도 다시 시작되지만 앱 다시 시작은 아무 것도 방해하지 않기 때문에 예외가 발생하지 않습니다.그러나 여전히 모든 진행 중인 세션이 손실되고, 앱이 다시 시작할 때 요청에 응답하지 않는 등의 문제가 발생합니다.
그럼 어쩌라는 거야?
이 동작을 비활성화하기 위한 몇 가지 해결 방법과 수정 사항이 있습니다. 디렉터리 연결, 레지스트리를 사용하여 FCN 끄기, Reflection을 사용하여 파일 변경 모니터 중지(노출된 방법이 없기 때문에). 하지만 FCN이 존재하는 이유가 있기 때문에 모두 잘못된 것 같습니다.데이터 구조가 아닌 앱 구조를 관리하는 것입니다.간단한 대답은 삭제할 폴더를 앱 외부에 배치하는 것입니다.FileChangesMonitor는 알림을 받지 않으며 앱이 매번 다시 시작되지 않습니다.예외는 없습니다.웹에서 볼 수 있도록 하려면 두 가지 방법이 있습니다.
들어오는 호출을 처리한 다음 앱 외부(wwwroot 외부)의 폴더에서 읽어 파일을 다시 제공하는 컨트롤러를 만듭니다.
프로젝트 규모가 크고 성능이 가장 중요한 경우 정적 콘텐츠를 제공하기 위해 작고 빠른 별도의 웹 서버를 설정합니다.따라서 당신은 IIS에 그의 특정 직업을 맡길 것입니다.동일한 시스템(윈도우즈의 경우 mongoose) 또는 다른 시스템(리눅스의 경우 nginx)에 있을 수 있습니다.좋은 소식은 리눅스에 정적 콘텐츠 서버를 설치하기 위해 추가 마이크로소프트 라이센스를 지불할 필요가 없다는 것입니다.
이게 도움이 되길 바랍니다.
이 문제는 디렉터리(또는 하위 디렉터리)에 경로 길이가 260개 이상인 파일이 있을 때 Windows에서 발생할 수 있습니다.
는 이한경삭합니다야해제우러를 해야 합니다.\\\\?\C:\mydir에 C:\mydir당신이 여기서 읽을 수 있는 260개의 기호 한계에 대해.
위에서 언급한 바와 같이 "승인된" 솔루션은 재분석 지점에서 실패합니다.기능을 올바르게 복제하는 훨씬 짧은 솔루션이 있습니다.
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);
}
나중에 언급한 권한 사례를 처리하지는 않지만, 모든 면에서 원본/스톡 디렉터리의 예상 기능을 훨씬 더 잘 제공합니다.삭제() - 코드를 훨씬 적게 사용합니다.
오래된 dir가 방해가 되지 않기 때문에 안전하게 처리를 계속할 수 있습니다... 파일 시스템이 계속 따라잡고 있기 때문에(또는 MS가 고장난 기능을 제공한 것에 대해 어떤 변명을 했더라도).
또한 대상 디렉터리가 크고 깊으며 대기(또는 예외가 발생할 경우)를 원하지 않는 경우 마지막 줄을 다음으로 바꿀 수 있습니다.
ThreadPool.QueueUserWorkItem((o) => { Directory.Delete(tfilename, recursive); });
당신은 여전히 일을 계속해도 안전합니다.
응용프로그램(또는 다른 응용프로그램)의 현재 디렉터리가 삭제하려는 디렉터리인 경우 액세스 위반 오류는 아니지만 디렉터리가 비어 있지는 않습니다.현재 디렉터리를 변경하여 자신의 응용 프로그램이 아닌지 확인하고 디렉터리가 다른 프로그램(예: Word, Excel, Total Commander 등)에서 열려 있지 않은지 확인합니다.대부분의 프로그램은 마지막으로 연 파일의 디렉터리에 CD로 저장되므로 이러한 문제가 발생합니다.
네트워크 파일의 경우 디렉터리.DeleteHelper(재귀적:=true)로 인해 파일 삭제 지연으로 인해 IOException이 발생할 수 있음
나는 메소드가 비동기식이고 다음과 같이 코드화되었을 때 언급된 문제의 가능성이 있는 한 가지 예를 해결했습니다.
// 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 문이 사용하는 문처럼 작동하는 것과 같습니다.
이 밀레니얼 기술로 해결했습니다(스레드를 떠날 수 있습니다).캐치에서 스스로 잠을 잡니다.
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);
Windows 탐색기 및 파일 핸들에 대한 많은 포괄적인 답변 외에도 경로가 너무 길 때 DirectoryNotFoundException이 발생했습니다.어떤 이유에서인지 우리의 압축 해제 코드는 270자 길이의 경로를 만들 수 있습니다.그것은 제 경우의 최대치인 260보다 더 많습니다.삭제하려고 할 때Directory.Delete(folder, recursive: true)디렉토리를 찾을 수 없다고 합니다.
편집: 오류가 간헐적이지 않기 때문에 모든 시도에서 오류가 발생하기 때문에 OP의 문제가 발생하지는 않았을 것입니다.
위의 답변 중 하나도 저에게 효과가 없었습니다.내 앱에서 사용하는 것으로 보입니다.DirectoryInfo대상 디렉터리에서 잠금 상태를 유지했습니다.
가비지 수집을 강제하는 것이 문제를 해결하는 데 도움이 되는 것처럼 보였지만 바로 해결되지는 않았습니다.필요한 경우 삭제를 몇 번 시도합니다.
에 하십시오.Directory.Exists예외가 발생하면 사라질 수 있기 때문입니다.왜 7
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.");
언급URL : https://stackoverflow.com/questions/329355/cannot-delete-directory-with-directory-deletepath-true
'programing' 카테고리의 다른 글
| 비동기의수면 대 시간.잠을 자다, 잠을 자다, 잠을 자다, 잠을 보다 (0) | 2023.05.14 |
|---|---|
| mongod --dbpath 설정 방법 (0) | 2023.05.14 |
| Mongo DB 4.0 Mongoose & NodeJs와의 트랜잭션, Express (0) | 2023.05.14 |
| 웹 작업 일정을 만드는 동안 오류가 발생했습니다. (0) | 2023.05.14 |
| Ubuntu 15.10에서 tar.gz 파일에서 Robomongo를 프로그램으로 설치하는 방법 (0) | 2023.05.14 |