폴더 또는 파일 크기 가져 오기


105

Java에서 폴더 또는 파일의 크기를 검색하려면 어떻게해야합니까?



당신이에 될 일 경우 안드로이드 다음에서보세요 StatFs. 파일 시스템 통계를 사용하며 우리의 필요에 따라 사용할 수 없었던 재귀 적 방법보다 거의 1000 배 더 빠릅니다. 우리의 구현은 다음에서 찾을 수 있습니다 : stackoverflow.com/a/58418639/293280
Joshua Pinter

답변:


191
java.io.File file = new java.io.File("myfile.txt");
file.length();

파일의 길이를 바이트 단위로 반환하거나 0파일이없는 경우 반환 합니다. 폴더 크기를 가져 오는 기본 제공 방법은 없습니다. 디렉토리 listFiles()를 나타내는 파일 객체 의 방법을 사용하여 디렉토리 트리를 재귀 적으로 살펴보고 직접 디렉토리 크기를 축적해야합니다.

public static long folderSize(File directory) {
    long length = 0;
    for (File file : directory.listFiles()) {
        if (file.isFile())
            length += file.length();
        else
            length += folderSize(file);
    }
    return length;
}

경고 :이 방법은 생산 용으로 충분히 견고하지 않습니다. directory.listFiles()반환 null되어 NullPointerException. 또한 심볼릭 링크를 고려하지 않으며 다른 오류 모드가있을 수 있습니다. 이 방법 사용 .


11
Windows 시스템의 C : 루트 디렉토리에서이를 실행하는 경우주의하십시오. (java.io.File에 따라) 파일도 디렉토리도 아닌 시스템 파일이 있습니다. 파일이 실제로 디렉토리인지 확인하기 위해 else 절을 ​​변경할 수 있습니다.
Paul Clapham

2
매개 변수를 확인하여 메서드 시작 부분에 디렉터리가 아닌지 확인하고 길이를 반환하는 간단한 변경으로 재귀가 더 간단 해집니다. 동일한 메서드에서 self에 대한 호출을 추가하면 대신 파일 참조 전달을 지원합니다. 디렉토리의.
Kevin Brock

3
Java 7 이상을 사용하는 경우 stackoverflow.com/a/19877372/40064 답변을 사용하면 훨씬 빠릅니다.
Wim Deblauwe 2015 년

1
이것은 심볼릭 링크에 의해 혼동 될 것입니다. 또한 NullPointerException디렉터리가 동시에 수정되면이 ( 가) 발생할 수 있습니다 .
Aleksandr Dubinsky

43

java-7 nio api를 사용하면 폴더 크기를 훨씬 빠르게 계산할 수 있습니다.

다음은 강력하고 예외를 발생시키지 않는 실행할 준비가 된 예제입니다. 입력 할 수 없거나 통과하는 데 문제가있는 디렉터리를 기록합니다. Symlink는 무시되며 디렉토리를 동시에 수정해도 필요 이상으로 문제가 발생하지 않습니다.

/**
 * Attempts to calculate the size of a file or directory.
 * 
 * <p>
 * Since the operation is non-atomic, the returned value may be inaccurate.
 * However, this method is quick and does its best.
 */
public static long size(Path path) {

    final AtomicLong size = new AtomicLong(0);

    try {
        Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {

                size.addAndGet(attrs.size());
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult visitFileFailed(Path file, IOException exc) {

                System.out.println("skipped: " + file + " (" + exc + ")");
                // Skip folders that can't be traversed
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult postVisitDirectory(Path dir, IOException exc) {

                if (exc != null)
                    System.out.println("had trouble traversing: " + dir + " (" + exc + ")");
                // Ignore errors traversing a folder
                return FileVisitResult.CONTINUE;
            }
        });
    } catch (IOException e) {
        throw new AssertionError("walkFileTree will not throw IOException if the FileVisitor does not");
    }

    return size.get();
}

Android 개발에 이에 상응하는 것이 있습니까?
안드로이드 개발자

AtomicLong대신 사용하는 이유가 long있습니까?
Lukas Schmelzeisen

익명 클래스에서 액세스 할 때 변수는 final
이어야합니다

1
JMH를 사용하여 벤치 마크를 수행했으며이 NIO API 방법은 commons-io 코드 (총 180229 개의 파일에 대해 많은 하위 폴더가있는 폴더에서 테스트 됨)에 비해 약 4 ~ 5 배 더 빠릅니다. Commons IO는 15 초, NIO는 5 초가 소요되었습니다.
Wim Deblauwe 2015 년

3
이 접근 방식이 가장 강력합니다. 심볼릭 링크, 동시 수정, 보안 예외를 처리하고 파일과 디렉토리 모두에서 작동합니다. 너무 나쁘고 Files직접 지원하지 않습니다!
Aleksandr Dubinsky

38

commons-ioFileUtils#sizeOfDirectory(File) 에서 필요합니다 .

비 디렉토리가 전달되면 메소드에서 예외가 발생하므로 파일이 디렉토리인지 수동으로 확인해야합니다.

경고 :이 메소드 (commons-io 2.4 기준)에는 버그 IllegalArgumentException가 있으며 디렉토리가 동시에 수정되면 발생할 수 있습니다 .


그렇다면 파일이 디렉토리가 아닌 경우 어떻게됩니까? 존재하지 않을 때?
etc-

@Mr_and_Mrs_D- checkDirectory(directory);확인 후 줄을 복사하여 붙여 넣으십시오 . File.listFiles자녀가 있는지 확인하십시오 . 참고 문헌 : FileUtils.sizeOfDirectory () , File.listFiles ()
씨 Polywhirl

3
버그 IO-449를 참조하십시오 . 이 메소드 IllegalArgumentException는 반복하는 동안 디렉토리가 수정되면를 발생시킵니다.
Aleksandr Dubinsky

아야!!! 짜증나 네요 ... 예, 파일을 나열하고 코드가 실행되는 동안 삭제되면 던집니다.
Dean Hiller

19

Java 8에서

long size = Files.walk(path).mapToLong( p -> p.toFile().length() ).sum();

사용하는 것이 더 좋을 것입니다 Files::size지도 단계에서 좋지만 확인 된 예외가 발생합니다.

업데이트 :
일부 파일 / 폴더에 액세스 할 수없는 경우 예외가 발생할 수 있음을 알고 있어야합니다. 이 질문Guava를 사용하는 다른 솔루션을 참조하십시오 .


1
나는 비슷한 것을 찾고 있었고 문제의 코드로 끝났습니다 : stackoverflow.com/questions/22867286/… , 오류 처리의 또 다른 측면이 문제를 일으키는 것을 알 수 있습니다.
AKSEL Willgert

@AkselWillgert 감사합니다. 이것은 유감스럽고 답변을 업데이트했습니다. 이제 Guava stackoverflow.com/a/24757556/1180621로
Andrejs 2014

10
public static long getFolderSize(File dir) {
    long size = 0;
    for (File file : dir.listFiles()) {
        if (file.isFile()) {
            System.out.println(file.getName() + " " + file.length());
            size += file.length();
        }
        else
            size += getFolderSize(file);
    }
    return size;
}

1
@Vishal 코드에는 간단한 수정이 필요합니다. 재귀 호출에서 크기를 할당하는 것이 아니라 기존 크기에 추가해야합니다. size += getFolderSize(file);
Teja Kantamneni

@Teja : 지적 해 주셔서 감사합니다.하지만 if 문에도 변경 사항이 적용됩니다
Vishal

가끔씩 증가하는 폴더에서 (다른 스레드가 파일과 폴더를 다운로드하고 동시에 폴더 크기를 인쇄 중입니다) "for (File file : dir.listFiles ()) {"줄에 nullpointerexception 을 제공합니다 . 일부 파일은 살아있는 폴더에 빠르게 나타나고 사라집니다. 그래서 for 루프 전에 dir.listFiles () 반환 값에 대한 null 검사를 추가했습니다 .
csonuryilmaz

File.listFiles () javadoc에서 : "디렉토리가 비어 있으면 배열이 비어 있습니다. 이 추상 경로 이름이 디렉토리를 나타내지 않거나 I / O 오류가 발생하면 null을 반환 합니다." 따라서 위의 설명은 동적으로 변경되는 폴더에서 폴더 크기를 가져올 때 유용합니다.
csonuryilmaz

7

를 들어 자바 팔 이 그것을 할 수있는 하나의 올바른 방법은 다음과 같습니다

Files.walk(new File("D:/temp").toPath())
                .map(f -> f.toFile())
                .filter(f -> f.isFile())
                .mapToLong(f -> f.length()).sum()

모든 디렉터리를 필터링하는 것이 중요 합니다. 길이 방법이 디렉터리에 대해 0이 될 수있는 것은 아니기 때문입니다.

적어도이 코드는 Windows 탐색기 자체와 동일한 크기 정보를 제공합니다.


4

일반적인 파일의 크기를 얻는 가장 좋은 방법은 다음과 같습니다 (디렉토리 및 비 디렉토리에서 작동).

public static long getSize(File file) {
    long size;
    if (file.isDirectory()) {
        size = 0;
        for (File child : file.listFiles()) {
            size += getSize(child);
        }
    } else {
        size = file.length();
    }
    return size;
}

편집 : 이것은 아마도 시간이 많이 걸리는 작업이 될 것입니다. UI 스레드에서 실행하지 마십시오.

또한 여기 ( https://stackoverflow.com/a/5599842/1696171 에서 가져옴 )는 반환 된 long에서 사용자가 읽을 수있는 문자열을 얻는 좋은 방법입니다.

public static String getReadableSize(long size) {
    if(size <= 0) return "0";
    final String[] units = new String[] { "B", "KB", "MB", "GB", "TB" };
    int digitGroups = (int) (Math.log10(size)/Math.log10(1024));
    return new DecimalFormat("#,##0.#").format(size/Math.pow(1024, digitGroups))
            + " " + units[digitGroups];
}

4

Java 8 NIO API 를 사용 하려면 다음 프로그램이 위치하는 디렉토리의 크기 (바이트)를 인쇄합니다.

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class PathSize {

    public static void main(String[] args) {
        Path path = Paths.get(".");
        long size = calculateSize(path);
        System.out.println(size);
    }

    /**
     * Returns the size, in bytes, of the specified <tt>path</tt>. If the given
     * path is a regular file, trivially its size is returned. Else the path is
     * a directory and its contents are recursively explored, returning the
     * total sum of all files within the directory.
     * <p>
     * If an I/O exception occurs, it is suppressed within this method and
     * <tt>0</tt> is returned as the size of the specified <tt>path</tt>.
     * 
     * @param path path whose size is to be returned
     * @return size of the specified path
     */
    public static long calculateSize(Path path) {
        try {
            if (Files.isRegularFile(path)) {
                return Files.size(path);
            }

            return Files.list(path).mapToLong(PathSize::calculateSize).sum();
        } catch (IOException e) {
            return 0L;
        }
    }

}

calculateSize방법은 Path개체에 보편적 이므로 파일에도 적용됩니다. 참고 파일이나 디렉토리에 액세스 할 수없는 경우,이 경우에는 반환 된 크기 경로 객체가 될 것입니다 0.


3

File.length()( Javadoc ).

이것은 디렉토리에서 작동하지 않거나 작동이 보장되지 않습니다.

디렉토리의 경우 무엇을 원하십니까? 모든 파일을 아래의이 전체 크기의 경우, 반복적으로 사용하여 아이들을 걸을 수 File.list()File.isDirectory()그들의 크기를 요약.


3

File객체는이 length방법을 :

f = new File("your/file/name");
f.length();

3
  • AndroidJava에서 작동
  • 폴더와 파일 모두에서 작동
  • 필요한 모든 곳에서 널 포인터를 확인합니다.
  • 바로 가기라고도하는 심볼릭 링크 무시
  • 생산 준비 완료!

소스 코드:

   public long fileSize(File root) {
        if(root == null){
            return 0;
        }
        if(root.isFile()){
            return root.length();
        }
        try {
            if(isSymlink(root)){
                return 0;
            }
        } catch (IOException e) {
            e.printStackTrace();
            return 0;
        }

        long length = 0;
        File[] files = root.listFiles();
        if(files == null){
            return 0;
        }
        for (File file : files) {
            length += fileSize(file);
        }

        return length;
    }

    private static boolean isSymlink(File file) throws IOException {
        File canon;
        if (file.getParent() == null) {
            canon = file;
        } else {
            File canonDir = file.getParentFile().getCanonicalFile();
            canon = new File(canonDir, file.getName());
        }
        return !canon.getCanonicalFile().equals(canon.getAbsoluteFile());
    }

1

Windows의 경우 java.io를 사용하면이 재귀 함수가 유용합니다.

    public static long folderSize(File directory) {
    long length = 0;

    if (directory.isFile())
         length += directory.length();
    else{
        for (File file : directory.listFiles()) {
             if (file.isFile())
                 length += file.length();
             else
                 length += folderSize(file);
        }
    }

    return length;
}

이것은 테스트를 거쳐 제대로 작동합니다.


1

테스트를 du -c <folderpath>했고 nio보다 2 배 빠릅니다. 파일 또는 재귀

private static long getFolderSize(File folder){
  if (folder != null && folder.exists() && folder.canRead()){
    try {
      Process p = new ProcessBuilder("du","-c",folder.getAbsolutePath()).start();
      BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
      String total = "";
      for (String line; null != (line = r.readLine());)
        total = line;
      r.close();
      p.waitFor();
      if (total.length() > 0 && total.endsWith("total"))
        return Long.parseLong(total.split("\\s+")[0]) * 1024;
    } catch (Exception ex) {
      ex.printStackTrace();
    }
  }
  return -1;
}

0
public long folderSize (String directory)
    {
        File curDir = new File(directory);
        long length = 0;
        for(File f : curDir.listFiles())
        {
            if(f.isDirectory())
            {               
                 for ( File child : f.listFiles()) 
                 {
                     length = length + child.length();
                 }

                System.out.println("Directory: " + f.getName() + " " + length + "kb");
            }
            else
            {
                length = f.length();
                System.out.println("File: " + f.getName() + " " + length + "kb");
            }
            length = 0;
        }
        return length;
    }

0

여기 StackOverflow에서 제안 된 다양한 솔루션을 많이 연구하고 조사한 후. 마침내 내 자신의 솔루션을 작성하기로 결정했습니다. 내 목적은 API가 폴더 크기를 가져올 수없는 경우 충돌을 원하지 않기 때문에 던지지 않는 메커니즘을 갖는 것입니다.이 방법은 다중 스레드 시나리오에 적합하지 않습니다.

우선 파일 시스템 트리를 탐색하면서 유효한 디렉토리를 확인하고 싶습니다.

private static boolean isValidDir(File dir){
    if (dir != null && dir.exists() && dir.isDirectory()){
        return true;
    }else{
        return false;
    }
}

둘째, 재귀 호출이 심볼릭 링크 (소프트 링크)로 이동하고 전체 집계에 크기를 포함하는 것을 원하지 않습니다.

public static boolean isSymlink(File file) throws IOException {
    File canon;
    if (file.getParent() == null) {
        canon = file;
    } else {
        canon = new File(file.getParentFile().getCanonicalFile(),
                file.getName());
    }
    return !canon.getCanonicalFile().equals(canon.getAbsoluteFile());
}

마지막으로 지정된 디렉토리의 크기를 가져 오는 재귀 기반 구현입니다. dir.listFiles ()에 대한 null 검사에 주목하십시오. javadoc에 따르면이 메소드는 null을 반환 할 수 있습니다.

public static long getDirSize(File dir){
    if (!isValidDir(dir))
        return 0L;
    File[] files = dir.listFiles();
    //Guard for null pointer exception on files
    if (files == null){
        return 0L;
    }else{
        long size = 0L;
        for(File file : files){
            if (file.isFile()){
                size += file.length();
            }else{
                try{
                    if (!isSymlink(file)) size += getDirSize(file);
                }catch (IOException ioe){
                    //digest exception
                }
            }
        }
        return size;
    }
}

케이크에 약간의 크림, 목록 파일의 크기를 가져 오는 API (루트 아래의 모든 파일 및 폴더 일 수 있음).

public static long getDirSize(List<File> files){
    long size = 0L;
    for(File file : files){
        if (file.isDirectory()){
            size += getDirSize(file);
        } else {
            size += file.length();
        }
    }
    return size;
}

0

리눅스에서 디렉토리를 정렬하려면 du -hs * | 정렬 -h


0

당신은 사용할 수 있습니다 Apache Commons IO쉽게 폴더 크기를 찾을 수 있습니다.

maven을 사용하는 경우 pom.xml파일에 다음 종속성을 추가 하십시오.

<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.6</version>
</dependency>

Maven의 팬이 아니라면 다음 jar를 다운로드하여 클래스 경로에 추가하십시오.

https://repo1.maven.org/maven2/commons-io/commons-io/2.6/commons-io-2.6.jar

public long getFolderSize() {

    File folder = new File("src/test/resources");
    long size = FileUtils.sizeOfDirectory(folder);

    return size; // in bytes
}

Commons IO를 통해 파일 크기를 얻으려면

File file = new File("ADD YOUR PATH TO FILE");

long fileSize = FileUtils.sizeOf(file);

System.out.println(fileSize); // bytes

또한 다음을 통해 달성 할 수 있습니다. Google Guava

Maven의 경우 다음을 추가합니다.

<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>28.1-jre</version>
</dependency>

Maven을 사용하지 않는 경우 클래스 경로에 다음을 추가하십시오.

https://repo1.maven.org/maven2/com/google/guava/guava/28.1-jre/guava-28.1-jre.jar

public long getFolderSizeViaGuava() {
        File folder = new File("src/test/resources");
        Iterable<File> files = Files.fileTreeTraverser()
                .breadthFirstTraversal(folder);
        long size = StreamSupport.stream(files.spliterator(), false)
                .filter(f -> f.isFile())
                .mapToLong(File::length).sum();

        return  size;
    }

파일 크기를 확인하려면

 File file = new File("PATH TO YOUR FILE");
 long s  = file.length();
 System.out.println(s);

0
private static long getFolderSize(Path folder) {
        try {
            return Files.walk(folder)
                      .filter(p -> p.toFile().isFile())
                      .mapToLong(p -> p.toFile().length())
                      .sum();
        } catch (IOException e) {
            e.printStackTrace();
            return 0L;
        }

귀하의 코드가 좋아 보이지만 다른 답변에 아무것도 추가하는지 잘 모르겠습니다. 그렇다면 답변을 수정하여 설명하십시오.
Dragonthoughts

적은 수의 코드로 동일한 작업을 수행하는 업데이트 된 버전 일뿐입니다.
Jaskaran Singh 19-12-24
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.