Получить размер папки или файла

105

Как я могу получить размер папки или файла в Java?

один
источник
То же самое, но с упором на эффективность: stackoverflow.com/questions/116574/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
Если вы используете 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и вызвать NullPointerException. Кроме того, он не учитывает символические ссылки и, возможно, имеет другие режимы сбоя. Воспользуйтесь этим методом .

Тендаи Мавуше
источник
11
Будьте осторожны, если вы запустите это в корневом каталоге C: на машине 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?
разработчик Android
Есть ли причина использовать AtomicLongвместо просто long?
Лукас Шмельцайзен
Переменная должна быть окончательной при доступе из анонимного класса
Аксель Виллгерт
1
Я провел тест с использованием JMH, и этот метод API NIO примерно в 4–5 раз быстрее по сравнению с кодом commons-io (протестирован в папке с множеством подпапок, всего 180229 файлов). Commons IO занял 15 секунд, NIO - 5 секунд.
Wim Deblauwe
3
Этот подход самый надежный. Он имеет дело с символическими ссылками, одновременным изменением, исключениями безопасности, работает как с файлами, так и с каталогами и т. Д. Жаль, что Filesон не поддерживает его напрямую!
Александр Дубинский
38

Вам нужно FileUtils#sizeOfDirectory(File)от commons-io .

Обратите внимание, что вам нужно будет вручную проверить, является ли файл каталогом, поскольку метод выдает исключение, если ему передается не каталог.

ПРЕДУПРЕЖДЕНИЕ : этот метод (по состоянию на commons-io 2.4) содержит ошибку и может вызывать ошибку, IllegalArgumentExceptionесли каталог одновременно изменяется.

Егор256
источник
Так что же происходит, когда файл не является каталогом? когда его не существует? и т. д. - какие ужасные документы
Mr_and_Mrs_D
@Mr_and_Mrs_D - Просто скопируйте и вставьте строки после checkDirectory(directory);проверки. Просто убедитесь, что у File.listFilesнего есть дети. Ссылки : FileUtils.sizeOfDirectory () , File.listFiles ()
Mr. 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
Андрейс
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;
}
Vishal
источник
1
@Vishal, ваш код должен иметь простое исправление, в рекурсивном вызове вы должны добавить размер к существующему размеру, а не просто назначить ему. size += getFolderSize(file);
Teja Kantamneni
@Teja: Спасибо, что указали, но изменения будут и в выражении if
Vishal
Иногда в растущей папке (другой поток загружает файлы и папки, и в то же время я печатаю размер папки по мере увеличения ) он выдает исключение nullpointerexception в строке «for (File file: dir.listFiles ()) {». Некоторые файлы быстро появляются и исчезают в живой папке. Поэтому я добавил нулевую проверку для возвращаемого значения dir.listFiles () перед циклом for.
csonuryilmaz
Из File.listFiles () javadoc: «Массив будет пустым, если каталог пуст. Возвращает null, если это абстрактное имя пути не обозначает каталог или если возникает ошибка ввода-вывода». Таким образом, приведенный выше комментарий полезен при получении размера папки для динамически меняющихся папок.
csonuryilmaz
7

Для Java 8 это один из правильных способов:

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

Важно отфильтровать все каталоги , поскольку не гарантируется, что метод length для каталогов будет равен 0.

По крайней мере, этот код предоставляет такую ​​же информацию о размере, как и сам проводник Windows.

Wumpz
источник
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 ) - хороший способ получить читаемую пользователем строку из возвращенного 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.

dinomario10
источник
3

File.length()( Javadoc ).

Обратите внимание, что это не работает для каталогов или не гарантируется.

Что вы хотите от каталога? Если это общий размер всех файлов под ним, вы можете рекурсивно пройтись с детьми, используя File.list()и, File.isDirectory()и суммировать их размеры.

данбен
источник
3

У Fileобъекта есть lengthметод:

f = new File("your/file/name");
f.length();
JesperE
источник
3
  • Работает для Android и Java
  • Работает как для папок, так и для файлов
  • Проверяет наличие нулевого указателя везде, где это необходимо
  • Игнорирует символические ссылки, известные как ярлыки
  • Производство готово!

Исходный код:

   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

для окон, использующих 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. Файлы или рекурсия

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;
}
G Dias
источник
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;
    }
}

Во-вторых, я не хочу, чтобы мой рекурсивный вызов переходил в символические ссылки (softlinks) и включал размер в общую совокупность.

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, этот метод может возвращать значение 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;
}
AB
источник
0

в linux, если вы хотите отсортировать каталоги, тогда du -hs * | sort -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;
        }
Джаскаран Сингх
источник
Хотя ваш код выглядит хорошо, я не уверен, что он что-то добавляет к другим ответам. Если да, то отредактируйте свой ответ, чтобы пояснить.
Драконьи мысли
Это просто обновленная версия выполнения той же работы с меньшим количеством строк кода.
Джаскаран Сингх