• 티스토리 홈
  • 프로필사진
    알쓸개잡
  • 방명록
  • 공지사항
  • 태그
  • 블로그 관리
  • 글 작성
알쓸개잡
  • 프로필사진
    알쓸개잡
    • 분류 전체보기 (92)
      • 스프링부트 (52)
      • AWS (5)
      • 쿠버네티스 (7)
      • 자바 (19)
      • 인프라 (0)
      • ETC (8)
  • 방문자 수
    • 전체:
    • 오늘:
    • 어제:
  • 최근 댓글
      등록된 댓글이 없습니다.
    • 최근 공지
        등록된 공지가 없습니다.
      • 반응형
      # Home
      # 공지사항
      #
      # 태그
      # 검색결과
      # 방명록
      • [Java] 특정 디렉토리의 파일 목록 가져오기
        2023년 11월 04일
        • 알쓸개잡
        • 작성자
        • 2023.11.04.:26

        Java API를 사용하여 숨겨진 파일을 포함하여 디렉터리에 있는 모든 파일을 재귀적으로 가져오는 방법에 대해서 알아보자.

        • Files.list()
        • Files.walk()
        • DirectorySystem
        • File.listFiles()
        • File.listFiles(filter)
        • Stream.filter()

         

        테스트를 위한 샘플 디렉토리 구조는 다음과 같다.

        샘플 디렉토리 구조

        sample-directory의 절대경로는 /java-project/blog/filelist/sample-directory이다.

         

        Directory의 파일만 리스팅

        Files.list()를 이용한 파일 목록 스트리밍

        하위 디렉터리와 하위 디렉토리 파일을 제외한 해당 디렉터리의 파일 목록만 가져올 때 사용한다.

        //samplePath의 Path 타입이고 경로는 /java-project/blog/filelist/sample-directory/ 이다.
        @Test
        void files_list_test() throws IOException {
            try (Stream<Path> pathStream = Files.list(samplePath)) {
                List<File> list =
                    pathStream
                        .map(Path::toFile)
                        .filter(File::isFile)
                        .toList();
                list.forEach(System.out::println);
            }
        }

         

        /java-project/blog/filelist/sample-directory/file2.txt
        /java-project/blog/filelist/sample-directory/file1.txt
        /java-project/blog/filelist/sample-directory/file4.extension
        /java-project/blog/filelist/sample-directory/file3.extension

         

         

        DirectoryStream을 이용한 파일 목록

        DirectoryStream은 looping을 사용하여 디렉터리의 항목을 반복하는 데 사용된다.

        DirectoryStream을 닫으면 스트림과 관련된 모든 리소스가 해제된다.

        스트림을 닫지 않으면 resource leak이 발생할 수 있으므로 try-with-resources 구문을 사용하는 것이 좋다.

        @Test
        void directory_stream_test() {
            List<File> fileList = new ArrayList<>();
            try (DirectoryStream<Path> stream = Files.newDirectoryStream(samplePath)){
                stream.forEach(path -> {
                    if (!Files.isDirectory(path)) {
                        fileList.add(path.toFile());
                    }
                });
            } catch (IOException e) {
                System.out.println("IOException " + e.getMessage());
            }
        
            fileList.forEach(System.out::println);
        }

         

        /java-project/blog/filelist/sample-directory/file2.txt
        /java-project/blog/filelist/sample-directory/file1.txt
        /java-project/blog/filelist/sample-directory/file4.extension
        /java-project/blog/filelist/sample-directory/file3.extension

         

        Directory의 하위 디렉터리를 포함한 파일 리스팅

        Files.walk()를 이용한 파일목록 스트리밍

        Files.walk() 메서드는 지정된 시작 디렉터리에서 시작하여 디렉토리 depth를 순회한 결과에 대한 stream을 반환한다.

        @Test
        void files_walk_test() {
            List<Path> pathList = new ArrayList<>();
            try (Stream<Path> pathStream = Files.walk(samplePath)) {
                pathList = pathStream.map(Path::normalize)
                    .filter(Files::isRegularFile)
                    .toList();
            } catch (IOException e) {
                System.out.println("IOException " + e.getMessage());
            }
        
            pathList.forEach(System.out::println);
        }

         

        /java-project/blog/filelist/sample-directory/file2.txt
        /java-project/blog/filelist/sample-directory/file1.txt
        /java-project/blog/filelist/sample-directory/directory2/directory2-2/directory2-2-file1
        /java-project/blog/filelist/sample-directory/directory2/directory2-1/directory2-1-file1
        /java-project/blog/filelist/sample-directory/file4.extension
        /java-project/blog/filelist/sample-directory/file3.extension
        /java-project/blog/filelist/sample-directory/directory1/directory1-2/directory1-2-file1
        /java-project/blog/filelist/sample-directory/directory1/directory1-1/directory1-1-file1

        하위 디렉터리의 파일을 포함한 목록을 출력하였다.

        하위 디렉터리를 포함하려면 filter(Files::isRegularFile)을 제거하면 된다.

        파일 목록이 아닌 디렉토리 목록만 출력하기 위해서는 filter(Files::isDirectory)로 수정하면 된다.

        @Test
        void files_walk_test() {
            List<Path> pathList = new ArrayList<>();
            try (Stream<Path> pathStream = Files.walk(samplePath)) {
                pathList = pathStream.map(Path::normalize)
                    .filter(Files::isDirectory)
                    .toList();
            } catch (IOException e) {
                System.out.println("IOException " + e.getMessage());
            }
        
            pathList.forEach(System.out::println);
        }

         

        /java-project/blog/filelist/sample-directory
        /java-project/blog/filelist/sample-directory/directory2
        /java-project/blog/filelist/sample-directory/directory2/directory2-2
        /java-project/blog/filelist/sample-directory/directory2/directory2-1
        /java-project/blog/filelist/sample-directory/directory1
        /java-project/blog/filelist/sample-directory/directory1/directory1-2
        /java-project/blog/filelist/sample-directory/directory1/directory1-1

         

        Recursion을 사용한 파일 목록

        File.isDirectory()와 File.listFiles()를 이용하여 재귀적으로 파일 목록을 가져올 수 있다.

        @Test
        void recursion_test() {
            List<File> files = listFiles(samplePath.toString());
            files.forEach(System.out::println);
        }
        
        private List<File> listFiles(String path) {
            List<File> fileList = new ArrayList<>();
            File[] files = new File(path).listFiles();
            for (File file : files) {
                if (file.isDirectory()) {
                    fileList.addAll(listFiles(file.getPath()));
                } else {
                    fileList.add(file);
                }
            }
        
            return fileList;
        }
        /java-project/blog/filelist/sample-directory/file2.txt
        /java-project/blog/filelist/sample-directory/file1.txt
        /java-project/blog/filelist/sample-directory/directory2/directory2-2/directory2-2-file1
        /java-project/blog/filelist/sample-directory/directory2/directory2-1/directory2-1-file1
        /java-project/blog/filelist/sample-directory/file4.extension
        /java-project/blog/filelist/sample-directory/file3.extension
        /java-project/blog/filelist/sample-directory/directory1/directory1-2/directory1-2-file1
        /java-project/blog/filelist/sample-directory/directory1/directory1-1/directory1-1-file1

         

        File 객체의 listFiles() 메서드의 경우 FileFilter 혹은 FilenameFilter를 인자로 전달하여 특정 조건의 파일 목록을 가져올 수 있다.

        FileFilter는 Predicate 유형의 함수형 인터페이스로써 다음과 같다.

        @FunctionalInterface
        public interface FileFilter {
        
            /**
             * Tests whether or not the specified abstract pathname should be
             * included in a pathname list.
             *
             * @param  pathname  The abstract pathname to be tested
             * @return  {@code true} if and only if {@code pathname}
             *          should be included
             */
            boolean accept(File pathname);
        }

         

        FilenameFilter 도 지원하는데 역시 BiPredicate 유형의 함수형 인터페이스로써 다음과 같다.

        @FunctionalInterface
        public interface FilenameFilter {
            /**
             * Tests if a specified file should be included in a file list.
             *
             * @param   dir    the directory in which the file was found.
             * @param   name   the name of the file.
             * @return  {@code true} if and only if the name should be
             * included in the file list; {@code false} otherwise.
             */
            boolean accept(File dir, String name);
        }

         

        FileFilter와 FilenameFilter는 람다 표현식으로 정의할 수 있는데 람다 표현식에 대해서는 다음 링크를 참고하기 바란다.

        2023.09.15 - [자바] - Java - 람다 표현식(lambda expression) - 4개의 주요 functional interface

        2023.09.10 - [자바] - Java - 람다 표현식 (lambda expression) 개요

         

        FileFilter와 FilenameFilter를 사용하여 특정 파일만 가져오거나 특정 확장자를 가진 파일만 가져오는 테스트 코드다.

        @Test
        void recursion_test() {
            //파일 목록에서 확장자가 .txt 인 파일 목록만 추출
            FilenameFilter filenameFilter =
                (file, name) ->	name.endsWith(".txt");
            
            //FileFilter를 대체하여 사용 가능하다.
            //물론 listFiles의 2번째 파라미터 타입은 FileFilter로 변경해야 한다.
            //FileFilter filter = file -> file.getName().endsWith(".txt");
        
            List<File> files = listFiles(samplePath.toString(), filenameFilter);
            files.forEach(System.out::println);
        }
        
        private List<File> listFiles(String path, FilenameFilter filter) {
            List<File> fileList = new ArrayList<>();
            File[] files = new File(path).listFiles(filter);
            for (File file : files) {
                if (file.isDirectory()) {
                    fileList.addAll(listFiles(file.getPath(), filter));
                } else {
                    fileList.add(file);
                }
            }
        
            return fileList;
        }

         

        /java-project/blog/filelist/sample-directory/file2.txt
        /java-project/blog/filelist/sample-directory/file1.txt

         

        *** 특정 확장자의 파일 목록을 가져오는 것은 Stream 방식을 사용하는 경우에도 filter를 통해서 다음과 같이 사용 가능하다.

        @Test
        void files_walk_extension_test() {
            List<Path> pathList = new ArrayList<>();
            try (Stream<Path> pathStream = Files.walk(samplePath)) {
                pathList = pathStream.map(Path::normalize)
                    .filter(Files::isRegularFile)
                    .filter(file -> file.getFileName().toString().endsWith(".extension"))
                    .toList();
            } catch (IOException e) {
                System.out.println("IOException " + e.getMessage());
            }
        
            pathList.forEach(System.out::println);
        }
        /java-project/blog/filelist/sample-directory/file4.extension
        /java-project/blog/filelist/sample-directory/file3.extension

         

        반응형
        저작자표시 비영리 변경금지

        '자바' 카테고리의 다른 글

        java21 - scoped value에 대해서 알아보자  (0) 2023.11.26
        java 21 처리량 향상을 위한 대안 - virtual thread 알아보자  (0) 2023.11.24
        java collection sort using Comparator  (0) 2023.10.17
        java generic class  (0) 2023.09.24
        java time convert (시간 변환)  (0) 2023.09.17
        다음글
        다음 글이 없습니다.
        이전글
        이전 글이 없습니다.
        댓글
      조회된 결과가 없습니다.
      스킨 업데이트 안내
      현재 이용하고 계신 스킨의 버전보다 더 높은 최신 버전이 감지 되었습니다. 최신버전 스킨 파일을 다운로드 받을 수 있는 페이지로 이동하시겠습니까?
      ("아니오" 를 선택할 시 30일 동안 최신 버전이 감지되어도 모달 창이 표시되지 않습니다.)
      목차
      표시할 목차가 없습니다.
        • 안녕하세요
        • 감사해요
        • 잘있어요

        티스토리툴바