Programing

Java를 사용하여 디렉토리의 파일 수 계산

lottogame 2020. 11. 30. 07:43
반응형

Java를 사용하여 디렉토리의 파일 수 계산


Java를 사용하여 디렉토리의 파일 수를 어떻게 계산합니까? 단순화를 위해 디렉토리에 하위 디렉토리가 없다고 가정합니다.

다음의 표준 방법을 알고 있습니다.

new File(<directory path>).listFiles().length

그러나 이것은 디렉토리의 모든 파일을 효과적으로 통과하므로 파일 수가 많으면 시간이 오래 걸릴 수 있습니다. 또한 파일의 수가 고정 된 큰 수 (예 : 5000)보다 크지 않으면 디렉토리의 실제 파일에 대해서는 신경 쓰지 않습니다.

나는 추측하고 있지만 디렉토리 (또는 Unix의 경우 i-node)에 포함 된 파일 수를 저장하지 않습니까? 파일 시스템에서 바로 그 번호를 얻을 수 있다면 훨씬 빠를 것입니다. 백엔드가 실제 처리를 시작하기 전에 Tomcat 서버의 모든 HTTP 요청에 대해이 검사를 수행해야합니다. 따라서 속도가 가장 중요합니다.

가끔씩 데몬을 실행하여 디렉토리를 지울 수 있습니다. 나는 그것을 알고 있으므로 그 해결책을 알려주지 마십시오.


이는 애플리케이션에 적합하지 않을 수 있지만 항상 기본 호출 (jni 또는 jna 사용)을 시도 하거나 플랫폼 별 명령을 실행하고 list (). length로 폴백 하기 전에 출력을 읽을 수 있습니다. * nix에서는 exec를 수행 할 수 있습니다 ls -1a | wc -l(참고-첫 번째 명령의 경우 대시 -1A이고 두 번째 명령의 경우 대시-소문자 -L입니다). Windows에서 무엇이 옳은지 잘 모르겠습니다. 아마도 dir요약을 찾아보십시오.

이와 같은 문제를 해결하기 전에 매우 많은 파일이있는 디렉토리를 만들고 list (). length가 실제로 너무 오래 걸리는지 확인하는 것이 좋습니다. 이 블로거가 제안 했듯이 , 당신은 이것을 땀을 흘리고 싶지 않을 수도 있습니다.

나는 아마도 Varkhan의 대답으로 갈 것입니다.


아 ... Java에서 간단한 방법을 사용하지 않는 이유는 파일 저장소 추상화입니다. 일부 파일 시스템은 쉽게 사용할 수있는 디렉토리에 파일 수가 없을 수 있습니다 ... 그 개수는 전혀 의미가 없을 수도 있습니다 ( 예를 들어 분산, P2P 파일 시스템, 파일 목록을 링크 된 목록으로 저장하는 fs 또는 데이터베이스 지원 파일 시스템 ...)을 참조하십시오. 그래,

new File(<directory path>).list().length

아마도 최선의 방법 일 것입니다.


Java 8부터 다음 세 줄로 수행 할 수 있습니다.

try (Stream<Path> files = Files.list(Paths.get("your/path/here"))) {
    long count = files.count();
}

5000 개의 자식 노드 및 inode 측면과 관련하여 :

이 방법은 항목을 반복하지만 Varkhan이 제안했듯이 JNI 또는 직접 시스템 명령 호출을 사용하는 것 외에 더 잘할 수는 없지만 이러한 방법이 동일한 작업을 수행하지 않는다는 것을 결코 확신 할 수 없습니다!

그러나 이것에 대해 조금 자세히 살펴 보겠습니다.

JDK8 소스를 보면, Files.list노출 스트림 를 사용 Iterable에서 Files.newDirectoryStream해당 대의원 FileSystemProvider.newDirectoryStream.

UNIX 시스템 (디 컴파일 됨 sun.nio.fs.UnixFileSystemProvider.class)에서는 반복자를로드합니다. A sun.nio.fs.UnixSecureDirectoryStream가 사용됩니다 (디렉토리를 반복하는 동안 파일 잠금 포함).

따라서 여기 항목을 반복하는 반복기가 있습니다.

이제 계산 메커니즘을 살펴 보겠습니다.

실제 개수는 Java 8 스트림에 의해 노출 된 개수 / 합계 감소 API에 의해 수행됩니다 . 이론적으로이 API는 많은 노력없이 (다중 읽기 사용) 병렬 작업을 수행 할 수 있습니다. 그러나 스트림은 병렬 처리가 비활성화 된 상태로 생성되므로 이동하지 않습니다.

이 접근 방식 좋은 점은 기본 (파일 시스템) API에서 읽을 때 항목이 반복기에 의해 계산되므로 메모리에 배열을로드하지 않는다는 것입니다.

마지막으로, 개념적으로 파일 시스템에서 정보의 경우 디렉토리 노드가 포함 된 파일 를 보유 할 필요가 없으며 하위 노드 목록 (inode 목록) 포함 할 수 있습니다 . 저는 파일 시스템 전문가는 아니지만 UNIX 파일 시스템이 그렇게 작동한다고 믿습니다. 따라서이 정보를 직접 가질 수있는 방법이 있다고 가정 할 수 없습니다 (예 : 어딘가에 숨겨진 자식 노드 목록이 항상있을 수 있음).


불행히도, 난 (하지만 이미 가장 좋은 방법이라고 생각 list()약간 더보다 listFiles()가 구성되지 않기 때문에, File객체).


총 숫자가 실제로 필요하지 않고 실제로 특정 숫자 (귀하의 경우 5000) 이후에 작업을 수행하고 싶기 때문에 java.nio.file.Files.newDirectoryStream. 장점은 카운트를 얻기 위해 전체 디렉토리를 거치지 않고 일찍 종료 할 수 있다는 것입니다.

public boolean isOverMax(){
    Path dir = Paths.get("C:/foo/bar");
    int i = 1;

    try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
        for (Path p : stream) {
            //larger than max files, exit
            if (++i > MAX_FILES) {
                return true;
            }
        }
    } catch (IOException ex) {
        ex.printStackTrace();
    }

    return false;
}

인터페이스 문서 에 대한 DirectoryStream도가 좋은 예제를 가지고있다.


실제로 (> 100'000) 많은 파일을 포함하는 디렉토리가있는 경우 다음과 같이 이동할 수 있습니다.

String directoryPath = "a path";

// -f flag is important, because this way ls does not sort it output,
// which is way faster
String[] params = { "/bin/sh", "-c",
    "ls -f " + directoryPath + " | wc -l" };
Process process = Runtime.getRuntime().exec(params);
BufferedReader reader = new BufferedReader(new InputStreamReader(
    process.getInputStream()));
String fileCount = reader.readLine().trim() - 2; // accounting for .. and .
reader.close();
System.out.println(fileCount);

시가를 사용하면 도움이 될 것입니다. Sigar 에는 통계를 얻기위한 기본 후크가 있습니다.

new Sigar().getDirStat(dir).getTotal()

Unfortunately, as mmyers said, File.list() is about as fast as you are going to get using Java. If speed is as important as you say, you may want to consider doing this particular operation using JNI. You can then tailor your code to your particular situation and filesystem.


public void shouldGetTotalFilesCount() {
    Integer reduce = of(listRoots()).parallel().map(this::getFilesCount).reduce(0, ((a, b) -> a + b));
}

private int getFilesCount(File directory) {
    File[] files = directory.listFiles();
    return Objects.isNull(files) ? 1 : Stream.of(files)
            .parallel()
            .reduce(0, (Integer acc, File p) -> acc + getFilesCount(p), (a, b) -> a + b);
}

참고URL : https://stackoverflow.com/questions/687444/counting-the-number-of-files-in-a-directory-using-java

반응형