[java] Java에서 재귀 적으로 디렉토리 삭제

Java에서 전체 디렉토리를 재귀 적으로 삭제하는 방법이 있습니까?

일반적인 경우 빈 디렉토리를 삭제할 수 있습니다. 그러나 내용이있는 전체 디렉토리를 삭제하는 경우 더 이상 간단하지 않습니다.

Java로 내용이 포함 된 전체 디렉토리를 어떻게 삭제합니까?



답변

Apache의 commons-io를 확인해야합니다 . 그것은 당신이 원하는 것을 할 FileUtils 클래스를 가지고 있습니다.

FileUtils.deleteDirectory(new File("directory"));


답변

Java 7을 사용하면 마지막 으로 안정적인 symlink 탐지를 통해이를 수행 할 수 있습니다 . (아파치의 commons-io는 현재 신뢰할 수있는 symlink 감지 기능 을 가지고 있다고 생각하지 않습니다.mklink .)

역사를 위해 자바 7 이전 답변이 있습니다.이 답변 은 심볼릭 링크따릅니다.

void delete(File f) throws IOException {
  if (f.isDirectory()) {
    for (File c : f.listFiles())
      delete(c);
  }
  if (!f.delete())
    throw new FileNotFoundException("Failed to delete file: " + f);
}


답변

Java 7 이상에서는 Files클래스 를 사용할 수 있습니다 . 코드는 매우 간단합니다.

Path directory = Paths.get("/tmp");
Files.walkFileTree(directory, 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 exc) throws IOException {
       Files.delete(dir);
       return FileVisitResult.CONTINUE;
   }
});


답변

시작 디렉토리를 포함하여 모든 파일과 디렉토리를 재귀 적으로 삭제하는 단일 라이너 솔루션 (Java8) :

Files.walk(Paths.get("c:/dir_to_delete/"))
                .map(Path::toFile)
                .sorted((o1, o2) -> -o1.compareTo(o2))
                .forEach(File::delete);

우리는 역순으로 비교자를 사용합니다. 그렇지 않으면 File :: delete는 비어 있지 않은 디렉토리를 삭제할 수 없습니다. 따라서 디렉토리를 유지하고 파일 만 삭제하려면 sorted ()에서 비교기를 제거 하거나 정렬을 완전히 제거하고 파일 필터를 추가하십시오.

Files.walk(Paths.get("c:/dir_to_delete/"))
                .filter(Files::isRegularFile)
                .map(Path::toFile)
                .forEach(File::delete);


답변

Java 7은 symlink 처리를 사용하여 디렉토리를 걷는 것에 대한 지원을 추가했습니다.

import java.nio.file.*;

public static void removeRecursive(Path path) throws IOException
{
    Files.walkFileTree(path, new SimpleFileVisitor<Path>()
    {
        @Override
        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
                throws IOException
        {
            Files.delete(file);
            return FileVisitResult.CONTINUE;
        }

        @Override
        public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException
        {
            // try to delete the file anyway, even if its attributes
            // could not be read, since delete-only access is
            // theoretically possible
            Files.delete(file);
            return FileVisitResult.CONTINUE;
        }

        @Override
        public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException
        {
            if (exc == null)
            {
                Files.delete(dir);
                return FileVisitResult.CONTINUE;
            }
            else
            {
                // directory iteration failed; propagate exception
                throw exc;
            }
        }
    });
}

나는 이것을 플랫폼 특정 메소드 (이 테스트되지 않은 코드에서)의 대체로 사용 합니다.

public static void removeDirectory(Path directory) throws IOException
{
    // does nothing if non-existent
    if (Files.exists(directory))
    {
        try
        {
            // prefer OS-dependent directory removal tool
            if (SystemUtils.IS_OS_WINDOWS)
                Processes.execute("%ComSpec%", "/C", "RD /S /Q \"" + directory + '"');
            else if (SystemUtils.IS_OS_UNIX)
                Processes.execute("/bin/rm", "-rf", directory.toString());
        }
        catch (ProcessExecutionException | InterruptedException e)
        {
            // fallback to internal implementation on error
        }

        if (Files.exists(directory))
            removeRecursive(directory);
    }
}

(SystemUtils는 Apache Commons Lang의 것 입니다. 프로세스는 개인용이지만 그 동작은 분명해야합니다.)


답변

방금 내 솔루션이 erickson과 거의 동일하고 정적 방법으로 패키지 된 것을 보았습니다. 이것을 어딘가에 떨어 뜨리면 (아시다시피) 아주 간단한 것을 위해 모든 Apache Commons를 설치하는 것보다 훨씬 가볍습니다.

public class FileUtils {
    /**
     * By default File#delete fails for non-empty directories, it works like "rm".
     * We need something a little more brutual - this does the equivalent of "rm -r"
     * @param path Root File Path
     * @return true iff the file and all sub files/directories have been removed
     * @throws FileNotFoundException
     */
    public static boolean deleteRecursive(File path) throws FileNotFoundException{
        if (!path.exists()) throw new FileNotFoundException(path.getAbsolutePath());
        boolean ret = true;
        if (path.isDirectory()){
            for (File f : path.listFiles()){
                ret = ret && deleteRecursive(f);
            }
        }
        return ret && path.delete();
    }
}


답변

스택이 있고 재귀 적 방법이없는 솔루션 :

File dir = new File("/path/to/dir");
File[] currList;
Stack<File> stack = new Stack<File>();
stack.push(dir);
while (! stack.isEmpty()) {
    if (stack.lastElement().isDirectory()) {
        currList = stack.lastElement().listFiles();
        if (currList.length > 0) {
            for (File curr: currList) {
                stack.push(curr);
            }
        } else {
            stack.pop().delete();
        }
    } else {
        stack.pop().delete();
    }
}