무한 재귀 폴더 제거 우리의 오래된 Server 2008 (R2 아님) 상자

어쨌든, 우리의 오래된 Server 2008 (R2 아님) 상자 중 하나는 무한히 반복되는 폴더를 개발했습니다. 백업 에이전트가 폴더로 재귀를 시도하고 다시는 돌아 오지 않기 때문에 백업과 함께 작동합니다.

폴더 구조는 다음과 같습니다.

C:\Storage\Folder1
C:\Storage\Folder1\Folder1
C:\Storage\Folder1\Folder1\Folder1
C:\Storage\Folder1\Folder1\Folder1\Folder1

… 등등. 그것은 90 년대에 우리 모두가 함께 사용 했던 Mandelbrot 세트 중 하나와 같습니다 .

난 노력 했어:

  • 탐색기에서 삭제합니다. 네, 저는 낙천주의 자입니다.
  • RMDIR C:\Storage\Folder1 /Q/S -이 반환 The directory is not empty
  • ROBOCOPY C:\temp\EmptyDirectory C:\Storage\Folder1 /PURGE -이것은 robocopy.exe가 충돌하기 전에 몇 분 동안 폴더를 회전합니다.

누구나이 폴더를 잘 제거하는 방법을 제안 할 수 있습니까?



답변

유용한 조언을 주신 모든 분들께 감사드립니다.

StackOverflow 영역에 잘 들어가서이 C # 코드 스 니펫을 두드려 문제를 해결했습니다. 긴 파일 경로에 액세스하는 문제를 구체적으로 해결 하는 Delimon.Win32.IO 라이브러리를 사용합니다 .

이것이 다른 누군가를 도울 수있는 경우를 대비하여 여기에 코드가 있습니다. 어쨌든 붙어있는 ~ 1600 레벨의 재귀를 통과했으며 모두 제거하는 데 약 20 분이 걸렸습니다.

using System;
using Delimon.Win32.IO;

namespace ConsoleApplication1
{
    class Program
    {
        private static int level;
        static void Main(string[] args)
        {
            // Call the method to delete the directory structure
            RecursiveDelete(new DirectoryInfo(@"\\server\\c$\\storage\\folder1"));
        }

        // This deletes a particular folder, and recurses back to itself if it finds any subfolders
        public static void RecursiveDelete(DirectoryInfo Dir)
        {
            level++;
            Console.WriteLine("Now at level " +level);
            if (!Dir.Exists)
                return;

            // In any subdirectory ...
            foreach (var dir in Dir.GetDirectories())
            {
                // Call this method again, starting at the subdirectory
                RecursiveDelete(dir);
            }

            // Finally, delete the directory, and any files below it
            Dir.Delete(true);
            Console.WriteLine("Deleting directory at level " + level);
            level--;
        }
    }
}

답변

재귀 연결 지점이 될 수 있습니다. 이러한 것은 Sysinternalsjunction 의 파일 및 디스크 유틸리티를 사용 하여 만들 수 있습니다 .

mkdir c:\Hello
junction c:\Hello\Hello c:\Hello

이제 c : \ Hello \ Hello \ Hello ….까지 끝없이 내려갈 수 있습니다 (MAX_PATH에 도달 할 때까지 대부분의 명령은 260 자, 일부 Windows API 함수는 32,767 자).

디렉토리 목록은 그것이 정션이라는 것을 보여줍니다.

C:\>dir c:\hello
 Volume in drive C is DR1
 Volume Serial Number is 993E-B99C

 Directory of c:\hello

12/02/2015  08:18 AM    <DIR>          .
12/02/2015  08:18 AM    <DIR>          ..
12/02/2015  08:18 AM    <JUNCTION>     hello [\??\c:\hello]
               0 File(s)              0 bytes
               3 Dir(s)  461,591,506,944 bytes free

C:\>

junction 유틸리티를 삭제하려면 다음을 수행하십시오.

junction -d c:\Hello\Hello

답변

답이 아니지만 의견을 제출할 충분한 담당자가 없습니다.

한 번 MS-DOS 시스템의 거대한 500MB FAT16 디스크에서이 문제를 해결했습니다. DOS 디버그를 사용하여 디렉토리 테이블을 수동으로 덤프하고 구문 분석했습니다. 그런 다음 재귀 디렉토리를 삭제 된 것으로 표시하기 위해 1 비트를 뒤집 었습니다. Dettman과 Wyatt ‘DOS Programmers’Reference ‘의 사본은 저에게 길을 보여주었습니다.

나는 여전히 이것을 자랑스럽게 생각합니다. FAT32 또는 NTFS 볼륨보다 강력한 기능을 갖춘 범용 도구가 있다면 놀랍습니다. 그 당시의 삶은 더 단순했습니다.


답변

Java는 긴 파일 경로를 처리 할 수도 있습니다. 그리고 훨씬 더 빨리 할 수 ​​있습니다. 이 코드 (Java API 문서에서 복사 한)는 약 1 초 (Windows 7, Java 8.0에서)에서 1600 수준의 딥 디렉토리 구조를 삭제하며 실제로 재귀를 사용하지 않기 때문에 스택 오버플로의 위험이 없습니다.

import java.nio.file.*;
import java.nio.file.attribute.*;
import java.io.*;

public class DeleteDir {

  static void deleteDirRecur(Path dir) throws IOException {
    Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
         @Override
         public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
             throws IOException
         {
             Files.delete(file);
             return FileVisitResult.CONTINUE;
         }
         @Override
         public FileVisitResult postVisitDirectory(Path dir, IOException e)
             throws IOException
         {
             if (e == null) {
                 Files.delete(dir);
                 return FileVisitResult.CONTINUE;
             } else {
                 throw e;
             }
         }
     });
  }

  public static void main(String[] args) throws IOException {
    deleteDirRecur(Paths.get("C:/Storage/Folder1"));
  }
}

답변

chdir디렉토리에 들어가고 상대 경로를 사용하는 경우 긴 경로 이름이 필요하지 않습니다 rmdir.

또는 POSIX 셸이 설치되어 있거나 DOS로 포팅 한 경우 :

# untested code, didn't bother actually testing since the OP already solved the problem.

while [ -d Folder1 ]; do
    mv Folder1/Folder1/Folder1/Folder1  tmp # repeat more times to work in larger batches
    rm -r Folder1     # remove the first several levels remaining after moving the main tree out
    # then repeat to end up with the remaining big tree under the original name
    mv tmp/Folder1/Folder1/.../Folder1 Folder1
    rm -r tmp
done

루프 조건에서 쉘 변수를 사용하여 이름을 바꾼 위치를 추적하는 것은 내가했던 것처럼 루프를 풀 때의 다른 대안입니다.

이렇게하면 KenD 솔루션의 CPU 오버 헤드를 피할 수 있습니다. 이로 인해 OS n는 새 수준이 추가 될 때마다 트리를 최상위에서 최상위 수준으로 이동하고 권한 등을 확인하므로 sum(1, n) = n * (n-1) / 2 = O(n^2)시간이 복잡합니다. 체인의 시작 부분에서 청크를 제거하는 솔루션 O(n)은 부모 디렉토리의 이름을 바꿀 때 Windows가 트리를 통과 해야하는 경우 가 아니면 안됩니다 . (Linux / Unix는 그렇지 않습니다.) OS가 모든 것을 검사 할 필요가 없다고 가정 할 때 chdir트리의 맨 아래까지 내려 가면서 경로를 chdir백업하고 디렉토리를 제거하는 솔루션 도 있어야 O(n)합니다. CD가있는 동안 작업을 수행 할 때 모든 시스템 호출마다 상위 디렉토리.

find Folder1 -depth -execdir rmdir {} +CD가 가장 깊은 디렉토리에있는 동안 rmdir을 실행합니다. 또는 실제로 find의 -delete옵션은 디렉토리에서 작동하며을 의미합니다 -depth. 그래서 find Folder1 -delete똑같은 일을하지만, 빨리해야한다. 그래, 리눅스에서 GNU의 발견은 다음 상대 경로와 하위 디렉토리에있는 디렉토리, CDing를 스캔하여 하강 rmdir한 후, 상대 경로로 chdir(".."). 오름차순으로 디렉토리를 다시 검색하지 않으므로 O(n)RAM 이 소비 됩니다.

: 그건 정말 근사했다 strace실제로 사용 쇼 unlinkat(AT_FDCWD, "tmp", AT_REMOVEDIR), open("..", O_DIRECTORY|...)fchdir(the fd from opening the directory)의 무리와 함께, fstat너무, 혼합 통화. 그러나 find가 실행되는 동안 디렉토리 트리가 수정되지 않으면 효과는 동일합니다.

편집 : 차기 만하면 GNU / Linux (Ubuntu 14.10, 2.4GHz 1 세대 Core2Duo CPU, WD 2.5TB Green Power drive (WD25EZRS)의 XFS 파일 시스템) 에서이 작업을 시도했습니다.

time mkdir -p $(perl -e 'print "annoyingfoldername/" x 2000, "\n"')

real    0m1.141s
user    0m0.005s
sys     0m0.052s

find annoyingfoldername/ | wc
   2000    2000 38019001  # 2k lines / 2k words / 38M characters of text


ll -R annoyingfoldername
... eventually
ls: cannot access ./annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername: File name too long
total 0
?????????? ? ? ? ?            ? annoyingfoldername

time find annoyingfoldername -delete

real    0m0.054s
user    0m0.004s
sys     0m0.049s

# about the same for normal rm -r,
# which also didn't fail due to long path names

(mkdir -p는 디렉토리 및 누락 된 경로 구성 요소를 작성합니다).

2k rmdir ops의 경우 실제로 0.05 초입니다. xfs는 메타 데이터 작업을 10 년 전과 같이 느리게 수정했기 때문에 저널에서 메타 데이터 작업을 일괄 처리하는 데 매우 능숙합니다.

ext4에서 create는 0m0.279s가었고 find는 여전히 0m0.074s가되었습니다.


답변

일부 Java 응용 프로그램에서했던 5000+ 디렉토리 깊이의 폴더 엉망과 같은 문제가 발생 했으며이 폴더를 제거하는 데 도움이되는 프로그램을 작성했습니다. 전체 소스 코드는 다음 링크에 있습니다.

https://imanolbarba.net/gitlab/imanol/DiREKT

그것은 잠시 후에 모든 것을 제거했지만 일을 처리했습니다. 나는 그것이 같은 좌절감을 느끼는 사람들에게 도움이되기를 바랍니다.


답변

나도 이것을 독립형 Windows 10 시스템에서 가지고있었습니다. C : \ User \ Name \ Repeat \ Repeat \ Repeat \ Repeat \ Repeat \ Repeat \ Repeat가 무한대로 보입니다.

Windows 또는 명령 프롬프트를 사용하여 약 50 번째까지 탐색 할 수 있습니다. 삭제하거나 클릭 할 수 없습니다.

C는 내 언어이므로 결국 시스템 호출 루프가있는 프로그램을 작성하여 실패 할 때까지 반복합니다. DOS 배치에서도 모든 언어 로이 작업을 수행 할 수 있습니다. tmp라는 디렉토리를 만들고 Repeat \ Repeat를 그 폴더로 옮기고 지금 비어있는 Repeat 폴더를 삭제 한 다음 tmp \ Repeat를 현재 폴더로 다시 옮겼습니다. 다시 반복하여!

 while (times<2000)
 {
  ChkSystem("move Repeat\\Repeat tmp");
  ChkSystem("rd Repeat");
  ChkSystem("move tmp\\Repeat Repeat");
  ++times;
  printf("Removed %d nested so far.\n", times);
 }

ChkSystem은 system () 호출을 실행하고 반환 값을 확인하여 실패하면 중지합니다.

중요한 것은 여러 번 실패했습니다. 내 프로그램이 작동하지 않거나 결국 너무 길다고 생각했습니다. 그러나 이전에 시스템 호출을 사용하여 동기화하지 않은 상태 에서이 작업을 수행 했으므로 프로그램을 다시 실행하고 중단 된 부분부터 계속 진행했기 때문에 프로그램이 작동하지 않는다고 즉시 생각하지 마십시오. 총 20 회 정도 실행 한 후 모두 해제했습니다. 전체적으로 원래 폴더 깊이는 약 1280 개였습니다. 그 원인을 알 수 없습니다. 미친.