1. 개요

이 빠른 사용방법(예제)에서는 디렉토리 내의 파일을 나열 하는 다양한 방법을 배웁니다 .

2. 상장

디렉토리를 참조하는 java.io.File 객체 의 listFiles() 메소드를 사용하여 디렉토리의 모든 파일을 나열할 수 있습니다 . 

public Set<String> listFilesUsingJavaIO(String dir) {
    return Stream.of(new File(dir).listFiles())
      .filter(file -> !file.isDirectory())
      .map(File::getName)
      .collect(Collectors.toSet());
}

보시다시피 listFiles() 는 디렉토리의 내용인 File 객체 의 배열을 반환합니다 .

우리는 그 배열에서 스트림을 생성할 것입니다. 그런 다음 하위 디렉터리가 아닌 모든 값을 필터링합니다. 마지막으로 결과를 집합으로 수집합니다.

List 대신 Set 유형을 선택했습니다 . 사실 listFiles() 에 의해 파일이 반환되는 순서는 보장되지 않습니다 .

새로 인스턴스화된 File 에서 listFiles() 메서드를 사용하면 null일 수 있으므로 약간의 주의 가 필요합니다. 제공된 디렉토리가 유효하지 않을 때 발생합니다. 결과적으로 NullPointerException 이 발생합니다 .

assertThrows(NullPointerException.class,
        () -> listFiles.listFilesUsingJavaIO(INVALID_DIRECTORY));

listFiles() 사용의 또 다른 단점은 전체 디렉토리를 한 번에 읽는다는 것입니다. 따라서 파일 수가 많은 폴더에 문제가 될 수 있습니다.

그래서 다른 방법을 논의해 봅시다.

3. 디렉토리 스트림

Java 7은 DirectoryStream 이라는 listFiles 의 대안을 도입했습니다 . 디렉토리의 내용을 반복하기 위해 for-each 구문과 잘 작동하도록 디렉토리 스트림이 생성되었습니다 . 이것은 한 번에 모든 것을 읽는 대신 디렉토리의 내용을 반복한다는 것을 의미합니다.

이것을 사용하여 디렉토리의 파일을 나열해 보겠습니다.

public Set<String> listFilesUsingDirectoryStream(String dir) throws IOException {
    Set<String> fileSet = new HashSet<>();
    try (DirectoryStream<Path> stream = Files.newDirectoryStream(Paths.get(dir))) {
        for (Path path : stream) {
            if (!Files.isDirectory(path)) {
                fileSet.add(path.getFileName()
                    .toString());
            }
        }
    }
    return fileSet;
}

위에서 try-with-resources 구성 을 통해 Java가 DirectoryStream 리소스 닫기를 처리하도록 했습니다. 마찬가지로 디렉토리를 필터링하는 폴더의 파일 세트를 반환합니다.

혼란스러운 이름에도 불구하고 DirectoryStream 은 Stream API 의 일부가 아닙니다 .

이제 Stream API를 사용하여 파일을 나열하는 방법을 살펴보겠습니다.

4. Java 8에 나열

Java 8은 java.nio.file.Files 에 새로운 list() 메소드를 도입했습니다 . list 메소드 는  느리게 채워진 디렉토리의 항목 스트림 을 반환합니다 .

4.1. Files.list() 사용

간단한 예를 살펴보겠습니다.

public Set<String> listFilesUsingFilesList(String dir) throws IOException {
    try (Stream<Path> stream = Files.list(Paths.get(dir))) {
        return stream
          .filter(file -> !Files.isDirectory(file))
          .map(Path::getFileName)
          .map(Path::toString)
          .collect(Collectors.toSet());
    }
}

마찬가지로 폴더에 포함된 파일 세트를 반환합니다. listFiles() 와 비슷해 보일 수 있지만 파일의 Path 를 얻는 방법이 다릅니다 .

여기서  list() 메서드는 디렉토리 항목을 느리게 채우는 Stream 객체를 반환합니다. 결과적으로 대용량 폴더를 보다 효율적으로 처리할 수 있습니다.

다시 한 번, 스트림 을 읽은 후 디렉터리 리소스가 닫히도록 try-with-resources 구성을 사용하여 스트림을 만들었습니다 .

4.2. File.list() 와의 비교

Files 클래스에서 제공 하는 list() 메서드를 File 객체 의 list () 메서드와 혼동해서는 안 됩니다. 후자는 디렉토리, 파일 및 디렉토리 모두의 모든 항목 이름의 문자열 배열을 반환합니다.

5. 걷기

파일을 나열하는 것 외에도 디렉토리를 직접 파일 항목보다 더 깊은 수준으로 탐색할 수 있습니다. 이 경우 Walk() 를 사용할 수 있습니다 .

public Set<String> listFilesUsingFileWalk(String dir, int depth) throws IOException {
    try (Stream<Path> stream = Files.walk(Paths.get(dir), depth)) {
        return stream
          .filter(file -> !Files.isDirectory(file))
          .map(Path::getFileName)
          .map(Path::toString)
          .collect(Collectors.toSet());
    }
}

Walk() 메서드 는 인수로 제공된 깊이 에서 디렉터리를 탐색합니다 . 여기에서 파일 트리를 탐색하고 모든 파일의 이름을 Set 으로 수집했습니다 .

또한 각 파일을 반복할 때 몇 가지 조치를 취하고 싶을 수도 있습니다. 이 경우 수행하려는 작업을 설명 하는 방문자 를 제공하여 walkFileTree() 메서드를 사용할 수 있습니다.

public Set<String> listFilesUsingFileWalkAndVisitor(String dir) throws IOException {
    Set<String> fileList = new HashSet<>();
    Files.walkFileTree(Paths.get(dir), new SimpleFileVisitor<Path>() {
        @Override
        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
            if (!Files.isDirectory(file)) {
                fileList.add(file.getFileName().toString());
            }
            return FileVisitResult.CONTINUE;
        }
    });
    return fileList;
}

이 방법은 이동하면서 파일을 추가로 읽고, 이동하거나 삭제하려는 경우에 유용합니다.

walk ( )walkFileTree() 메서드는 디렉터리 대신 유효한 파일을 전달하려고 하면 NullPointerException 을 throw하지 않습니다. 실제로 Stream 은 제공된 파일 자체인 적어도 하나의 요소를 반환하도록 보장합니다.

Set<String> expectedFileSet = Collections.singleton("test.xml");
String filePathString = "src/test/resources/listFilesUnitTestFolder/test.xml";
assertEquals(expectedFileSet, listFiles.listFilesUsingFileWalk(filePathString, DEPTH));

6. 결론

이 짧은 기사에서는 디렉토리 내의 파일을 나열하는 다양한 방법을 살펴보았습니다.

먼저 listFiles() 를 사용하여 폴더의 모든 내용을 가져왔습니다. 그런 다음 DirectoryStream 을 사용 하여 디렉토리 콘텐츠를 지연 로드했습니다. 또한 Java 8에 도입된 list() 메서드도 사용했습니다.

마지막으로 파일 트리 작업을 위한 walk()walkFileTree() 메서드를 시연했습니다.

항상 그렇듯이 예제의 전체 소스 코드는 GitHub에서 사용할 수 있습니다 .

Generic footer banner