디렉터리의 파일 나열
File 클래스의 list() 메서드를 사용하면 디렉터리에 있는 모든 파일의 파일 이름을 쉽게 나열할 수 있습니다. 파일 이름 이외의 파일을 가져오려면 listFiles() 메서드를 사용할 수 있습니다. 이것은 매우 간단합니다. 어려운 것은 반환된 목록을 처리하는 방법입니다. 기존의 긴 외부 반복자를 사용하는 대신 우아한 기능적 표현을 사용하여 실제로 이 목록을 탐색합니다. 여기서는 JDK의 새로운 CloseableStream 인터페이스와 일부 관련 고차 함수도 사용해야 합니다.
다음 코드는 현재 디렉터리에 있는 모든 파일의 이름을 나열합니다.
다음과 같이 코드 코드를 복사합니다.
Files.list(Paths.get("."))
.forEach(System.out::println);
다른 디렉터리를 나열하려면 "."를 액세스하려는 디렉터리의 전체 경로로 바꾸면 됩니다.
여기서는 먼저 Paths의 get() 메서드를 사용하여 문자열을 통해 Path 인스턴스를 생성합니다. 그런 다음 Files 도구 클래스의 list() 메서드를 통해 ClosableStream 개체를 얻고 이를 사용하여 디렉터리의 모든 파일을 탐색할 수 있습니다. 그런 다음 내부 반복자 forEach()를 사용하여 파일 이름을 인쇄합니다. 먼저 이 코드의 출력 결과 중 일부를 살펴보겠습니다. 현재 디렉터리의 파일과 하위 디렉터리를 나열합니다.
다음과 같이 코드 코드를 복사합니다.
./aSampleFiles.txt
./큰 상자
./fpij
...
파일이 아닌 현재 디렉터리의 하위 디렉터리만 가져오려면 filter() 메서드를 사용할 수 있습니다.
다음과 같이 코드 코드를 복사합니다.
Files.list(Paths.get("."))
.filter(파일::is디렉토리)
.forEach(System.out::println);
ilter() 메서드는 파일 스트림에서 디렉터리를 필터링합니다. 람다 표현식을 전달하는 대신 Files 클래스의 isDirectory 메서드에 대한 참조를 전달합니다. filter() 메서드에는 부울 값을 반환하는 Predicate 유형이 필요하며 이 메서드가 적합하다는 점을 기억하세요. 마지막으로 내부 반복자를 사용하여 디렉토리 이름을 인쇄합니다. 프로그램은 현재 디렉토리의 하위 디렉토리를 인쇄합니다.
다음과 같이 코드 코드를 복사합니다.
./큰 상자
./fpij
./산출
...
이 방식으로 작성하는 것이 훨씬 간단하며 Java로 작성하는 기존 방식에 비해 많은 코드를 절약합니다. 특정 패턴과 일치하는 파일을 나열하는 방법을 살펴보겠습니다.
디렉토리에 지정된 파일 나열
Java는 오랫동안 파일 이름 필터링을 위해 list() 메서드의 변형을 제공했습니다. 이 버전의 list() 메서드는 FilenameFilter 유형의 매개 변수를 허용합니다. 이 인터페이스에는 두 개의 매개변수인 File dir(디렉토리를 나타냄)과 String name(파일 이름을 나타냄)을 허용하는 하나의 accept() 메소드만 있습니다. accept() 메서드가 true를 반환하면 파일 이름이 반환된 목록에 표시되고, 그렇지 않으면 표시되지 않습니다. 이 방법을 구현해 보겠습니다.
일반적인 접근 방식은 FilenameFilter 인터페이스를 구현하는 익명 내부 클래스의 인스턴스를 list() 메서드에 전달하는 것입니다. 예를 들어, 이 메서드를 사용하여 fpij 디렉터리에 .java 파일을 반환하는 방법을 살펴보겠습니다.
다음과 같이 코드 코드를 복사합니다.
최종 String[] 파일 =
new File("fpij").list(new java.io.FilenameFilter() {
public boolean accept(최종 파일 디렉토리, 최종 문자열 이름) {
return name.endsWith(".java");
}
});
System.out.println(파일);
몇 줄의 코드를 작성하려면 실제로 시간과 노력이 필요합니다. 이런 종류의 코드는 객체 생성, 함수 호출, 익명 내부 클래스 정의, 클래스에 메서드 삽입 등 너무 복잡합니다. 우리는 더 이상 이러한 고통을 견딜 필요가 없습니다. 두 개의 매개 변수를 받아들이고 bollean을 반환하는 람다 식을 전달하기만 하면 됩니다. 나머지는 Java 컴파일러가 처리합니다.
이전 예제에서는 익명 내부를 람다 식으로 간단히 바꿀 수 있지만 추가 최적화의 여지가 있습니다. 새로운 DirectoryStream 도구를 사용하면 대규모 디렉터리 구조를 보다 효율적으로 탐색할 수 있습니다. 이 방법을 시도해 보겠습니다. 이는 추가 필터를 허용하는 newDirectoryStream() 메서드의 변형입니다.
다음과 같이 코드 코드를 복사합니다.
Files.newDirectoryStream(
Paths.get("fpij"), 경로 -> path.toString().endsWith(".java"))
.forEach(System.out::println);
이렇게 하면 익명의 내부 클래스를 제거하고 번거로운 코드를 간결하고 명확하게 만듭니다. 두 버전의 출력은 동일합니다. 지정된 파일을 인쇄해 보겠습니다.
이 코드는 지정된 디렉터리의 .java 파일만 출력합니다. 출력의 일부는 다음과 같습니다.
다음과 같이 코드 코드를 복사합니다.
fpij/Compare.java
fpij/IterateString.java
fpij/ListDirs.java
...
파일 이름을 기준으로 파일을 필터링합니다. 파일의 실행 가능 여부, 읽기 가능 여부, 쓰기 가능 여부 등의 파일 속성을 기준으로 쉽게 필터링할 수도 있습니다. 이를 수행하려면 FileFilter 유형의 매개변수를 허용하는 listFiles() 메소드가 필요합니다. 익명의 내부 클래스를 만드는 대신 여전히 람다 식을 사용합니다. 이제 현재 디렉터리의 모든 숨겨진 파일을 나열하는 예를 살펴보겠습니다.
다음과 같이 코드 코드를 복사합니다.
final File[] files = new File(".").listFiles(file -> file.isHidden());
큰 디렉터리를 운영하는 경우 File에서 메서드를 직접 호출하는 대신 DirectoryStream을 사용할 수 있습니다.
listFiles() 메서드에 전달하는 람다 식의 서명은 FileFilter 인터페이스의 accept() 메서드 서명과 동일합니다. 이 람다 식은 File 인스턴스의 매개 변수를 허용합니다. 이 예에서 매개 변수 이름은 file입니다. 파일에 숨겨진 속성이 있으면 true를 반환하고 그렇지 않으면 false를 반환합니다.
실제로 여기에서 코드를 더욱 간소화할 수 있습니다. 메서드 참조를 전달하면 코드가 더 간결해 보입니다.
다음과 같이 코드 코드를 복사합니다.
new File(".").listFiles(파일::isHidden);
먼저 람다 식을 사용하여 구현한 다음 메서드 참조를 사용하여 더 간결하게 리팩토링했습니다. 새로운 코드를 작성한다면 당연히 이 간결한 방법을 사용해야 합니다. 이러한 깔끔한 구현을 조기에 발견할 수 있다면 우리는 확실히 이를 사용하는 것을 우선시할 것입니다. "먼저 작동하게 한 다음 더 좋게 만드세요"라는 말이 있습니다. 먼저 코드를 실행하게 하세요. 이를 명확히 한 후 최적화를 위해 단순성과 성능을 고려하겠습니다.
예제를 사용하여 디렉터리에서 지정된 파일을 필터링합니다. 지정된 디렉터리 아래의 하위 디렉터리를 탐색하는 방법을 살펴보겠습니다.