Java - 디렉토리, 하위 파일 모두 삭제하는 방법

File.delete()를 이용하면 1개의 파일이나 폴더를 삭제할 수 있지만, 디렉토리(폴더)의 하위 경로에 있는 파일들은 삭제를 할 수 없습니다.

이런 경우 하위의 모든 파일들을 찾아서 삭제를 하도록 구현하거나, 이런 내용이 구현되어있는 자바 라이브러리를 사용하여 삭제해야 합니다.

1. 모든 하위 폴더, 파일 삭제 (Recursively)

먼저 재귀적으로 하위 파일들을 모두 찾아 삭제하는 코드를 소개합니다.

저는 /home/js/test/myfolder 경로에 폴더를 만들었고 그 하위에 폴더와 파일들을 많이 만들었습니다. tree 명령어로 구조를 보면 아래와 같습니다.

/home/js/test/myfolder$ tree
.
├── file1.txt
├── folder1
│   └── file2.txt
├── folder2
│   ├── file3.txt
│   └── file4.txt
├── folder3
│   ├── file5.txt
│   ├── file6.txt
│   └── folder4
│       ├── text2.txt
│       ├── text3.txt
│       └── text.txt
└── myscript.sh

아래 코드는 /home/js/test/myfolder 폴더를 포함한 모든 하위 파일들을 재귀적(recursive)으로 삭제하는 코드입니다.

import java.io.File;
import java.text.ParseException;

public class Example {

    public static void main(String args[]) throws ParseException {
        File rootDir = new File("/home/js/test/myfolder");
        deleteFilesRecursively(rootDir);
    }

    static boolean deleteFilesRecursively(File rootFile) {
        File[] allFiles = rootFile.listFiles();
        if (allFiles != null) {
            for (File file : allFiles) {
                deleteFilesRecursively(file);
            }
        }
        System.out.println("Remove file: " + rootFile.getPath());
        return rootFile.delete();
    }
}

File이 폴더라면 listFiles()는 그 하위의 파일들을 리스트로 리턴해줍니다. File이 폴더가 아니라면 null을 리턴합니다.

실행하면 다음과 같은 로그가 출력되면서 모든 파일이 삭제됩니다.

Remove file: /home/js/test/myfolder/folder1/file2.txt
Remove file: /home/js/test/myfolder/folder1
Remove file: /home/js/test/myfolder/file1.txt
Remove file: /home/js/test/myfolder/myscript.sh
Remove file: /home/js/test/myfolder/folder3/file5.txt
Remove file: /home/js/test/myfolder/folder3/folder4/text3.txt
Remove file: /home/js/test/myfolder/folder3/folder4/text2.txt
Remove file: /home/js/test/myfolder/folder3/folder4/text.txt
Remove file: /home/js/test/myfolder/folder3/folder4
Remove file: /home/js/test/myfolder/folder3/file6.txt
Remove file: /home/js/test/myfolder/folder3
Remove file: /home/js/test/myfolder/folder2/file3.txt
Remove file: /home/js/test/myfolder/folder2/file4.txt
Remove file: /home/js/test/myfolder/folder2
Remove file: /home/js/test/myfolder

2. FileUtils 라이브러리로 하위 폴더, 파일 삭제

위의 예제처럼 직접 구현하는 것이 번거롭고 귀찮다면 commons-io 라이브러리의 FileUtils를 이용할 수 있습니다.

Gradle 프로젝트는 build.gradle의 dependencies에 다음과 같이 추가합니다.

dependencies {
  compile group: 'commons-io', name: 'commons-io', version: '2.6'
  ...
}

Maven 등의 다른 빌드시스템을 사용하는 프로젝트는 mvnrepository.com을 참고하셔서 설정하시면 됩니다.

FileUtils.deleteDirectory()는 인자로 전달되는 파일 및 하위 파일들을 모두 삭제합니다.

아래 코드는 위에서 직접 구현한 코드와 동일한 기능을 수행합니다. 코드를 실행해보면 myfolder의 하위 파일들이 모두 삭제된 것을 확인할 수 있습니다.

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;

public class Example {

    public static void main(String args[]) {
        try {
            File rootDir = new File("/home/js/test/myfolder");
            FileUtils.deleteDirectory(rootDir);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

FileUtils 내부에 모든 것이 구현되어있어서 가장 깔끔하고 간편한 방법입니다.

3. Files.walk()으로 하위 폴더, 파일 삭제

Java8의 Stream과 Files을 이용하여 파일을 삭제할 수 있습니다.

다음과 같이 모든 파일을 순회하면서 파일을 삭제할 수 있습니다.

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;

public class Example {

    public static void main(String args[]) {
        try {
            File rootDir = new File("/home/js/test/myfolder");
            FileUtils.deleteDirectory(rootDir);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

위 코드를 실행하면 다음처럼 로그를 출력하면서 파일을 삭제합니다.

Remove file: /home/js/test/myfolder/myscript.sh
Remove file: /home/js/test/myfolder/folder3/folder4/text3.txt
Remove file: /home/js/test/myfolder/folder3/folder4/text2.txt
Remove file: /home/js/test/myfolder/folder3/folder4/text.txt
Remove file: /home/js/test/myfolder/folder3/folder4
Remove file: /home/js/test/myfolder/folder3/file6.txt
Remove file: /home/js/test/myfolder/folder3/file5.txt
Remove file: /home/js/test/myfolder/folder3
Remove file: /home/js/test/myfolder/folder2/file4.txt
Remove file: /home/js/test/myfolder/folder2/file3.txt
Remove file: /home/js/test/myfolder/folder2
Remove file: /home/js/test/myfolder/folder1/file2.txt
Remove file: /home/js/test/myfolder/folder1
Remove file: /home/js/test/myfolder/file1.txt
Remove file: /home/js/test/myfolder

다음과 같이 forEach에 인자로 전달한 Lambda 대신에 File::delete를 사용할 수도 있습니다.

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Comparator;

public class Example {

    public static void main(String args[]) {
        try {
            File rootDir = new File("/home/js/test/myfolder");
            Files.walk(rootDir.toPath())
                    .sorted(Comparator.reverseOrder())
                    .map(Path::toFile)
                    .forEach(File::delete);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

특정 파일만 삭제하도록 구현하려면 forEach에서 조건문을 추가하여 특정 파일만 삭제할 수도 있습니다.

References

Loading script...
codechachaCopyright ©2019 codechacha