Java 디렉토리의 파일을 어떻게 반복합니까?


175

모든 하위 디렉토리의 파일을 포함하여 디렉토리의 모든 파일 목록을 가져와야합니다. Java로 디렉토리 반복을 수행하는 표준 방법은 무엇입니까?

답변:


207

File#isDirectory()주어진 파일 (경로)이 디렉토리인지 테스트 하는 데 사용할 수 있습니다 . 이 인 경우 true동일한 메소드를 다시 호출하여 File#listFiles()결과를 얻습니다. 이것을 재귀 라고 합니다.

기본 시작 예는 다음과 같습니다.

public static void main(String... args) {
    File[] files = new File("C:/").listFiles();
    showFiles(files);
}

public static void showFiles(File[] files) {
    for (File file : files) {
        if (file.isDirectory()) {
            System.out.println("Directory: " + file.getName());
            showFiles(file.listFiles()); // Calls same method again.
        } else {
            System.out.println("File: " + file.getName());
        }
    }
}

이것은 StackOverflowError트리가 JVM 스택이 보유 할 수있는 것보다 깊을 때에 민감합니다 . 대신 반복적 인 접근 방식이나 꼬리 재귀 를 사용하고 싶을 수도 있지만 다른 주제입니다.)


감사합니다 Balus, 그것이 일반적인 추측만큼 얼마나 깊은 지에 대한 아이디어가 있습니까?
James

10
JVM의 메모리 설정에 따라 다릅니다. 그러나 일반적으로 몇 천 정도입니다. 만약 당신이 그런 디렉토리에 빠졌다고 생각한다면 재귀를 사용하지 마십시오.
Mike Baranczak

4
이것은 NullPointerException파일 시스템이 호출 사이에서 변경 될 때 isDirectory와 블록 또는 당신이 정말로 운이 좋지 listFiles않을 때 발생할 수있는 것처럼 변할 수 있습니다 System.out.println. 의 출력이 listFilesnull이 아닌지 확인하면 해당 경쟁 조건이 해결됩니다.
Mike Samuel

1
@BoratSagdiyev, 오래된 Java 파일 API를 사용하지 않지만 최신 JVM java.nio.file.DirectoryStream을 사용하는 경우 디렉토리를 반복 할 수 있으며 작은 메모리 공간을 갖도록 구현할 수 있지만 확실한 방법은 다음과 같습니다. 특정 플랫폼에서 메모리 사용량을 모니터링합니다.
Mike Samuel

1
"C : \\"폴더가 가장 좋은 예는 아닙니다.)
Vyacheslav

86

Java 1.7을 사용중인 경우 다음을 사용할 수 있습니다. java.nio.file.Files.walkFileTree(...) .

예를 들면 다음과 같습니다.

public class WalkFileTreeExample {

  public static void main(String[] args) {
    Path p = Paths.get("/usr");
    FileVisitor<Path> fv = new SimpleFileVisitor<Path>() {
      @Override
      public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
          throws IOException {
        System.out.println(file);
        return FileVisitResult.CONTINUE;
      }
    };

    try {
      Files.walkFileTree(p, fv);
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

}

Java 8을 사용하는 경우 다음과 함께 스트림 인터페이스를 사용할 수 있습니다 java.nio.file.Files.walk(...).

public class WalkFileTreeExample {

  public static void main(String[] args) {
    try (Stream<Path> paths = Files.walk(Paths.get("/usr"))) {
      paths.forEach(System.out::println);
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

}

1
새 디렉토리를 걷거나 함수를 실행할 때 검사 점을 넣는 방법이 있습니까?
Raghu DV

28

Apache Commons 의 FileUtils 클래스, 특히 iterateFiles를 확인하십시오 .

지정된 디렉토리 (및 선택적으로 서브 디렉토리)의 파일을 반복 할 수 있습니다.


5
이 API는 실제로 스트리밍되지 않으며 (mem 사용에 관심이있는 경우) 먼저 컬렉션을 생성 한 다음 반복자를 반환합니다. return listFiles (directory, fileFilter, dirFilter) .iterator ();
길리 나훔

Java 1.6에 적합한 옵션입니다.
David I.

@GiliNachum에 동의하십시오. Apache의 FileUtils는 먼저 모든 파일을 수집하고이를위한 반복자를 제공합니다. 대량의 파일이 있으면 리소스에 해 롭습니다.
Bogdan Samondros

8

Java 7+의 경우 https://docs.oracle.com/javase/7/docs/api/java/nio/file/DirectoryStream.html있습니다.

Javadoc에서 가져온 예제 :

List<Path> listSourceFiles(Path dir) throws IOException {
   List<Path> result = new ArrayList<>();
   try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, "*.{c,h,cpp,hpp,java}")) {
       for (Path entry: stream) {
           result.add(entry);
       }
   } catch (DirectoryIteratorException ex) {
       // I/O error encounted during the iteration, the cause is an IOException
       throw ex.getCause();
   }
   return result;
}

8

사용 org.apache.commons.io.FileUtils

File file = new File("F:/Lines");       
Collection<File> files = FileUtils.listFiles(file, null, true);     
for(File file2 : files){
    System.out.println(file2.getName());            
} 

서브 디렉토리에서 파일을 원하지 않으면 false를 사용하십시오.


3

그것은 나무이기 때문에 재귀는 친구입니다. 부모 디렉토리로 시작하고 메소드를 호출하여 자식 파일 배열을 가져옵니다. 자식 배열을 반복합니다. 현재 값이 디렉토리이면 메소드의 재귀 호출에 전달하십시오. 그렇지 않으면 리프 파일을 적절하게 처리하십시오.


2

언급했듯이 이것은 재귀 문제입니다. 특히, 당신은보고 싶어 할 수 있습니다

listFiles() 

자바 파일 API 에서 here . 디렉토리에있는 모든 파일의 배열을 리턴합니다. 이것과 함께 사용

isDirectory()

더 재귀가 필요한지 확인하는 것이 좋습니다.


링크 는 답변의 링크가 끊어 졌기 때문에 사용 중일 수 있습니다.
Donglecow

0

@msandiford 응답으로 추가하기 위해, 파일 트리를 걸을 때 대부분의 경우 디렉토리 또는 특정 파일을 방문 할 때 기능을 실행하려고 할 수 있습니다. 스트림을 사용하는 것을 꺼려한다면. 다음 메소드를 재정의 할 수 있습니다.

Files.walkFileTree(Paths.get(Krawl.INDEXPATH), EnumSet.of(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE,
    new SimpleFileVisitor<Path>() {
        @Override
        public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
                throws IOException {
                // Do someting before directory visit
                return FileVisitResult.CONTINUE;
        }
        @Override
        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
                throws IOException {
                // Do something when a file is visited
                return FileVisitResult.CONTINUE;
        }
        @Override
        public FileVisitResult postVisitDirectory(Path dir, IOException exc)
                throws IOException {
                // Do Something after directory visit 
                return FileVisitResult.CONTINUE;
        }
});

0

파일 순회에 File.list (FilenameFilter) 및 변형을 잘못 사용할 수도 있습니다. 짧은 코드이며 초기 Java 버전에서 작동합니다. 예 :

// list files in dir
new File(dir).list(new FilenameFilter() {
    public boolean accept(File dir, String name) {
        String file = dir.getAbsolutePath() + File.separator + name;
        System.out.println(file);
        return false;
    }
});
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.