Отримати розмір папки чи файлу


105

Як я можу отримати розмір папки чи файлу на Java?


Те ж саме , але з акцентом на ефективність: stackoverflow.com/questions/116574 / ...
Чіро Сантіллі郝海东冠状病六四事件法轮功

Якщо ви трапляєтесь на Android, то подивіться StatFs. Він використовує статистику файлової системи і майже в 1000 разів швидше рекурсивних методів, які були непридатними для наших потреб. Нашу реалізацію можна знайти тут: stackoverflow.com/a/58418639/293280
Джошуа Пінтер

Відповіді:


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і викликати a NullPointerException. Крім того, він не враховує посилання і, можливо, має інші режими відмов. Використовуйте цей метод .


11
Будьте обережні, якщо запустити це в каталозі C: ​​root на машині Windows; там є системний файл, який (за даними java.io.File) не є ні файлом, ні каталогом. Ви можете змінити пункт else, щоб перевірити, чи Файл є насправді каталогом.
Пол Клафам

2
Проста зміна, щоб перевірити параметр, щоб побачити, чи це не каталог на початку методу, і повернути довжину, тоді рекурсія простіша - просто додайте виклик self у тому самому методі, і тоді це підтримує передачу файлової посилання натомість також каталогу.
Кевін Брок

3
Якщо ви використовуєте Java 7 або новішої версії , використовуйте відповідь stackoverflow.com/a/19877372/40064, це набагато швидше.
Вім Деблауве

1
Це буде плутати символьні посилання. Крім того, він може кидати а, NullPointerExceptionякщо каталог одночасно змінено.
Олександр Дубінський,

43

Використовуючи java-7 nio api, обчислення розміру папки можна зробити набагато швидше.

Ось готовий для запуску приклад, який є надійним і не кидає винятку. Він буде вести каталоги, до яких він не може входити, або у них виникли проблеми з переходом. Посилання символів ігноруються, і одночасна модифікація каталогу не спричинить більше проблем, ніж потрібно.

/**
 * 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?
Лукас Шмельцейзен

Ця змінна повинна бути остаточною при доступі з анонімного класу
Аксель Вілгерт

1
Я зробив орієнтир, використовуючи JMH, і цей метод NIO api приблизно в 4 - 5 разів швидший порівняно з кодом commons-io (перевірений у папці з багатьма папками на загальну кількість 180229 файлів). Commons IO зайняв 15 секунд, NIO - 5 секунд.
Вім Деблауве

3
Цей підхід є найбільш надійним. Він стосується символьних посилань, одночасних модифікацій, винятків із безпеки, працює як з файлами, так і з каталогами тощо. Це дуже погано Files, не підтримує це безпосередньо!
Олександр Дубінський

38

Вам потрібно FileUtils#sizeOfDirectory(File)від commons-io .

Зауважте, що вам потрібно буде вручну перевірити, чи файл є каталогом, оскільки метод викидає виняток, якщо до нього передається не-каталог.

ПОПЕРЕДЖЕННЯ . У цьому методі (як у commons-io 2.4) є помилка і може викинутись, IllegalArgumentExceptionякщо каталог одночасно змінено.


Отже, що відбувається, коли файл не є каталогом? коли його не існує? тощо - як жахливі документи
Mr_and_Mrs_D

@Mr_and_Mrs_D - Просто скопіюйте та вставте рядки після checkDirectory(directory);перевірки. Просто переконайтесь, що File.listFilesє діти. Відгуки : FileUtils.sizeOfDirectory () , File.listFiles ()
Містер Polywhirl

3
Дивіться про помилку IO-449 . Цей метод буде кидати, IllegalArgumentExceptionякщо каталог змінено під час його ітерації.
Олександр Дубінський

ой !!! Це смокче ... так, він перераховує файли, а потім, якщо один видалений під час роботи коду, він кидає.
Дін Хіллер

19

На Java 8:

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

Було б приємніше використовувати Files::sizeв кроці карти, але це кидає перевірений виняток.

ОНОВЛЕННЯ:
Ви також повинні знати, що це може спричинити виняток, якщо деякі файли / папки недоступні. Дивіться це питання та інше рішення, використовуючи Guava .


1
я розглядав щось подібне і закінчив питання про код: stackoverflow.com/questions/22867286/… , як ви бачите, є ще один аспект обробки помилок, що також спричиняє проблеми.
Аксель Вілгерт

@AkselWillgert Спасибі, це прикро, і я оновив відповідь. Тепер переходимо до Guava stackoverflow.com/a/24757556/1180621
Andrejs

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
@Вішал вашого коду повинен мати просте виправлення, у рекурсивному дзвінку ви повинні додати розмір до існуючого розміру, а не просто призначити його. size += getFolderSize(file);
Teja Kantamneni

@Teja: Дякую за вказівку, але зміни будуть і у заяві if
Vishal

Іноді у зростаючої папці (інший потік завантажує файли та папки, і в той же час я друкую розмір папки з прогресуванням), вона дає nullpointerexception у рядку "for (Файл файлу: dir.listFiles ()) {". Деякі файли з’являються і швидко зникають у живій папці. Тому я додав нульову перевірку повернення значення dir.listFiles () раніше для циклу.
csonuryilmaz

З File.listFiles () javadoc: "Масив буде порожнім, якщо каталог порожній. Повертає нуль, якщо це абстрактне ім'я шляху не позначає каталог, або якщо виникає помилка вводу / виводу." Тому вище коментар корисний при отриманні розміру папки на динамічно змінюваних папках.
csonuryilmaz

7

Для Java 8 це один із правильних способів:

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

Важливо відфільтрувати всі каталоги , оскільки метод довжини не гарантовано дорівнює 0 для каталогів.

Принаймні, цей код надає інформацію такого самого розміру, як і сам Windows Explorer.


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;
}

Редагувати: Зауважте, що це, ймовірно, буде трудомісткою операцією. Не запускайте його на потоці інтерфейсу користувача.

Також тут (взято з https://stackoverflow.com/a/5599842/1696171 ) є приємним способом отримати зручну для читання користувачу String з давно повернутого:

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

Якщо ви хочете використовувати API Java 8 NIO , наступна програма надрукує розмір каталогу в байтах у байтах.

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
  • Працює для Android та Java
  • Працює як для папок, так і для файлів
  • Перевіряє нульовий вказівник скрізь, де потрібно
  • Ігнорує символічне посилання aka ярлики
  • Продукція готова!

Вихідний код:

   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>і в 2 рази швидше, ніж nio.Files або рекурсія

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 (). На думку javadoc, існує ймовірність, що цей метод може повернутись до нуля.

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

в Linux, якщо ви хочете сортувати каталоги, то 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, завантажте наступну банку і додайте її до шляху класу.

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;
        }

Хоча ваш код виглядає добре, я не впевнений, що він додає нічого до інших відповідей. Якщо це так, то, будь ласка, відредагуйте свою відповідь, щоб пояснити.
Драгонтаути

Це просто оновлена ​​версія виконувати ту саму роботу в менших рядках коду.
Яскаран Сінгх
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.