[Java] 하위 폴더 및 파일 삭제 (재귀 함수 포함)

    자바로 파일을 직접 컨트롤하여 파일을 삭제해야 하는 경우 및 혹은 하위 디렉토리까지 삭제를 해야 하는 경우가 있을 수 있다. 예를 들어 로그 파일을 매일 폴더를 생성하여 관리를 하고 있는데 날짜값이 오래되었으면 삭제를 해야 한다면, 자바로 날짜값을 접근하여 폴더를 삭제하거나 폴더명을 날짜값으로 만들 경우 제거하는 경우가 있다.

     

    이번에 할 것은 날짜값을 체크해서 삭제하는 것이 아니라, 특정 폴더를 지정하면 하위 폴더를 모두 제거하는 로직을 해보도록 한다.

     

    [Java] 하위 폴더 및 파일 삭제 (재귀 함수)

     


     

    테스트 데이터

    테스트 하기에 앞서 로직의 실험을 위해 우선 폴더를 생성하였는데 아래와 같이 D드라이브에 test라는 폴더를 만들었으며 해당 폴더 안에는 여러개의 하위 폴더들을 생성하였고, test 폴더 안에는 test.txt라는 파일이 존재한다.

     

    테스트 용 폴더

     

    test 폴더 내에서 가장 깊은 폴더는 아래와 같이 test -> test_sub2 -> test_sub2_1 폴더까지 있으며, 이 폴더에는 test_2_1.txt 파일이 존재한다.

     

    가장 깊은 폴더

     

     

    테스트는 D:\test라는 인자값을 주는 것으로 시작하며, 이 인자값에 있는 하위 폴더와 파일을 삭제하는 것이 목표이다.

     

    고전적인 방식

    우선 고전적인 방식부터 설명해보고자 한다. 별다른 라이브러리를 사용하지 않고 오로지 파일 객체를 사용하며 Java 8에서 지원하는 Stream을 활용하는 방식이 아니다.

     

    이렇게 고전적인 방식은 보통 코드를 복잡하지만 속도가 빨라서 하나 만들어 놓으면 매우 요긴하게 쓸 수 있기에 필자같은 경우 프로젝트를 하면 내가 직접 만든 메소드를 CommonUtil이라는 클래스에 넣어서 필요할때 꺼내 쓰는 방식을 많이 사용한다.

     

    import java.io.File;
    
    public class Main {
    
        public static void main(String args[]) {
            scanDelete("D:/test");
        }
    
        public static void scanDelete(String filePath) {
            File[] files = new File(filePath).listFiles();
    
            for(File file : files) {
                // 우선 폴더 리스트를 가져온다.
                if (file.isFile()) {
                    file.delete();
                    System.out.println(file.getName() + " 파일 삭제.");
                } else {
                    scanDelete(file.getAbsolutePath());
                    file.delete();
                    System.out.println(file.getName() + " 폴더 삭제.");
                }
            }
        }
    }

     

    실행 결과

    test.txt 파일 삭제.
    test_sub1 폴더 삭제.
    test_2.txt 파일 삭제.
    test_2_1.txt 파일 삭제.
    test_sub2_1 폴더 삭제.
    test_sub2 폴더 삭제.
    test_sub3 폴더 삭제.

    간단한 메소드로 위와 같은 내용이 가능한 이유는 재귀함수의 위력 때문이다. 우선 기본적으로 파일을 스캔하는데 파일을 만나게 될 경우 파일을 삭제하고 폴더일 경우 다시 자신의 함수를 호출하게 되어, 하위 폴더로 이동하게 된다. 하위 폴더에서 역시 마찬가지로 파일은 지우고, 폴더를 만나면 이동을 하게 되는데 더이상 이동을 하지 못하면 이전 함수로 돌아오게 된다.

     

     

    재귀 함수를 호출한 이후에는 file을 delete하며, 폴더를 삭제했다라는 문구를 출력하게 되면서, 폴더를 삭제한다. 이 로직은 위의 실행 결과 순서대로 보면 이해하기 쉬울 것이다. 

     

    재귀 함수 실행 모습

     

    결과는 위와 같이 깔끔하게 하위 폴더와 파일들이 삭제가 된 모습이다. 생각보다 메소드가 간단하기 때문에 이런 메소드를 만들어서 필요할 때 꺼내쓰면 나중에 개발 속도가 올라간 모습을 볼 수 있을 것이다.

     

    Java 8 이상 Stream 방식

    두번째 설명할 방식은 Java 8 이상에서 지원하는 Stream으로 서브 폴더와 파일들을 삭제하는 방식이다.

     

    public static void streamSubDelete(String filePath) {
        try {
            File baseDir = new File(filePath);
            Files.walk(baseDir.toPath())
                    .sorted(Comparator.reverseOrder())
                    .map(Path::toFile)
                    .forEach((file)->{
                        file.delete();
                        if(file.isDirectory()) {
                            System.out.println(file.getName() + " 폴더 삭제.");
                        } else {
                            System.out.println(file.getName() + " 파일 삭제.");
                        }
                    });
        } catch (Exception e) {
            e.printStackTrace();
        }
    
        // 마지막에 폴더 생성
        File f = new File(filePath);
        f.mkdir();
    }

     

    이 방식을 쓰면, 지정한 패스까지 삭제를 하기 때문에 마지막에 폴더를 생성하는 로직을 넣었다. 보다시피 stream은 java 8이상에서만 지원이 되며, 로직을 보면 Exception을 넣어야 하기에 개인적으로 선호하는 스타일은 아니다. 다만 재귀 호출 없이 즉, 별도의 메소드를 호출할 필요가 없다는 장점이 있어서, 특정 메소드 내에 넣어서 사용하면 이 방식이 편리할 수도 있다. 

     

    실행결과

    test.txt 파일 삭제.
    sub_folder_3 파일 삭제.
    test_2.txt 파일 삭제.
    test_2_1.txt 파일 삭제.
    sub_folder_2_1 파일 삭제.
    sub_folder_2 파일 삭제.
    sub_folder_1 파일 삭제.
    test 파일 삭제.

     

     

    댓글

    Designed by JB FACTORY