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에서 사용할 수 있습니다 .