Как узнать размер файла java

Обновлено: 30.06.2024

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

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

File Объект имеет length метод:

Это возвращает длину файла в байтах или 0 если файл не существует. Не существует встроенного способа получить размер папки, вам придется ходить по дереву каталогов рекурсивно (используя listFiles() метод файлового объекта, представляющего каталог) и накапливать размер каталога для себя:

Предупреждение: этот метод недостаточно надежен для производственного использования. directory.listFiles() может вернуться null и вызвать а NullPointerException . Кроме того, он не учитывает символьные ссылки и, возможно, имеет другие режимы сбоя. Используйте этот метод .

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

Предупреждение: этот метод (от commons-io 2.4) имеет ошибку и может бросить IllegalArgumentException , если каталог одновременно изменяется.

Используя api NIO java-7, вычисление размера папки может быть сделано намного быстрее.

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

Было бы лучше использовать Files::size в шаге карты, но это вызывает проверенное исключение.

Обновление:
Вы также должны знать, что это может вызвать исключение, если некоторые файлы/папки недоступны. См. этот вопрос и другое решение с помощью Guava .

Вот лучший способ получить общий размер файла (работает для каталогов и не каталогов):

Edit: обратите внимание, что это, вероятно, займет много времени. Не запускайте его в потоке пользовательского интерфейса.

После многих исследований и изучения различных решений, предлагаемых здесь, в StackOverflow. В конце концов я решил написать собственное решение. Моя цель состоит в том, чтобы иметь механизм no-throw, потому что я не хочу аварийно завершить работу, если API не может получить размер папки. Этот метод не подходит для многопоточного сценария.

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

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

Наконец, моя реализация на основе рекурсии для получения размера указанного каталога. Обратите внимание на проверку null для dir.listFiles(). Согласно javadoc есть возможность, что этот метод может вернуть null.

Некоторые сливки на торте, API, чтобы получить размер списка файлов (может быть все файлы и папки под root).

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

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

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

Если вы хотите использовать Java 8 NIO API, следующая программа напечатает размер, в байтах, каталога, в котором она находится.

calculateSize Метод универсален для Path объектов, поэтому он также работает для файлов.
Обратите внимание, что если файл или каталог недоступны, в этом случае будет возвращен размер объекта path 0 .

Во-первых, не забывайте, потому что вы можете подумать, что это обычный вопрос, но это не так. Я знаю, как узнать размер файла и каталога с помощью file.length и Apache FileUtils.sizeOfDirectory .

Моя проблема в том, что в моем случае размер файлов и каталогов слишком велик (в сотнях мб). Когда я пытаюсь узнать размер, используя приведенный выше код (например, создавая файловый объект), моя программа становится настолько требовательной к ресурсам, что снижает производительность.

Есть ли способ узнать размер файла без создания объекта?

Я использую для файлов File file1 = new file (fileName); длинный размер = file1.length ();

А для каталога File dir1 = new file (dirPath); длинный размер = fileUtils.sizeOfDirectiry (dir1);

У меня есть один параметр, который позволяет вычислять размер. Если параметр false, то все идет гладко. Если false, программа тормозит или зависает. Я рассчитываю размер 4 каталогов и 2 файлов базы данных.

Отвечая на мой собственный вопрос ..

Это не лучшее решение, но в моем случае работает ..

Я создал пакетный скрипт, чтобы получить размер каталога, а затем прочитать его в java-программе. Это дает мне меньше времени выполнения, когда количество файлов в каталоге больше 1L (это всегда в моем случае) .. sizeOfDirectory занимает около 30255 мс, а с пакетным сценарием я получаю 1700 мс .. Для меньшего количества файлов пакетный сценарий дорог .

Я добавлю к тому, что ответил Питер Лоури, и добавлю, что когда в каталоге много файлов (напрямую, а не в подкаталогах) - время, необходимое для file.listFiles() , это очень медленно (у меня нет точные цифры, знаю по опыту). Количество файлов должно быть большим, несколько тысяч, если я правильно помню - если это ваш случай, то fileUtils на самом деле попытается загрузить все их имена сразу в память, что может потребовать больших затрат.

Если это ваша ситуация, я бы предложил реструктурировать каталог, чтобы иметь какую-то иерархию, которая обеспечит небольшое количество файлов в каждом подкаталоге.

У нас была аналогичная проблема производительности с File.listFiles () в каталогах с большим количеством файлов.

Наша установка представляла собой одну папку с 10 подпапками по 10 000 файлов в каждой. Папка находилась в общей сетевой папке, а не на машине, на которой выполнялся тест.

Мы использовали FileFilter, чтобы принимать только файлы с известными расширениями или каталогом, чтобы мы могли обратиться к каталогам.

Профилирование показало, что около 70% времени было потрачено на вызов File.isDirectory (который, как я предполагаю, вызывает Apache). Было два вызова isDirectory для каждого файла (один в фильтре и один на этапе обработки файла).

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

Изменение порядка проверки в фильтре для проверки действительного имени перед действительным каталогом сэкономило много времени, но нам все равно нужно было вызвать isDirectory для рекурсивного поиска.

Мое решение заключалось в том, чтобы реализовать версию listFiles в собственном коде, которая возвращала бы структуру данных, содержащую все метаданные о файле, а не только имя файла, как это делает File.

Это устранило проблему производительности, но добавило проблему обслуживания, связанную с необходимостью поддержки нативного кода разработчиками Java (к счастью, мы поддерживали только одну ОС).

Файл - это просто оболочка для пути к файлу. Не имеет значения, насколько велик файл, только его имя.

Если вы хотите получить размер всех файлов в каталоге, ОС должна прочитать каталог, а затем найти каждый файл, чтобы узнать его размер. Каждый доступ занимает около 10 мс (потому что это типичное время поиска для жесткого диска). Таким образом, если у вас есть 100 000 файлов, вам потребуется около 17 минут, чтобы получить все их размеры.

Единственный способ ускорить это - получить более быструю поездку. например Твердотельные накопители имеют среднее время поиска 0,1 мс, но для получения файла размером 100 КБ все равно потребуется 10 секунд или более.

Кстати: размер каждого файла не имеет значения, потому что он фактически не читает файл. Только запись файла, имеющая размер.

РЕДАКТИРОВАТЬ: Например, если я попытаюсь получить размеры большого каталога. Сначала это происходит медленно, но после кэширования данных становится намного быстрее.

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

Время FileUtils.sizeOfDirectory ("/ usr") занимает менее 8,7 секунд. Это относительно медленно по сравнению со временем, которое требуется du, но он обрабатывает около 30К файлов в секунду.

Альтернативным вариантом может быть запуск Runtime.exec("du -s "+directory); , однако разница будет не больше нескольких секунд. Большую часть времени, вероятно, будет потрачено на ожидание диска, если он не находится в кеше.

Файловые объекты очень легкие. Либо с вашим кодом что-то не так, либо проблема не в файловых объектах, а в доступе HD, необходимом для получения размера файла. Если вы сделаете это для большого количества файлов (скажем, десятков тысяч), то жесткий диск будет выполнять множество поисков, что в значительной степени является самой медленной операцией, возможной на современном ПК (на несколько порядки величины).

Это возвращает длину файла в байтах или 0 , если файл не существует. Нет никакого встроенного способа получить размер папки, вам придется рекурсивно пройти дерево каталогов (используя метод listFiles() файлового объекта, который представляет каталог), и скопируйте размер каталога для себя:

ПРЕДУПРЕЖДЕНИЕ. Этот метод недостаточно эффективен для использования в производстве. directory.listFiles() может возвращать null и вызывать NullPointerException . Кроме того, он не рассматривает символические ссылки и, возможно, имеет другие режимы отказа. Используйте этот метод.

Используя java-7 nio api, вычисление размера папки может быть выполнено намного быстрее.

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

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

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

Было бы лучше использовать Files::size на шаге карты, но он выдает исключенное исключение.

UPDATE:
Вы также должны знать, что это может вызвать исключение, если некоторые из файлов/папок недоступны. Смотрите question и другое решение, используя Guava.

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

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

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

Если вы хотите использовать API Java 8 NIO, следующая программа будет печатать размер в байтах каталога, в котором он находится.

Метод calculateSize универсален для объектов Path , поэтому он также работает для файлов. Примечание, что если файл или каталог недоступны, в этом случае возвращаемый размер объекта пути будет 0 .

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

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

Объект File имеет метод length :

Здесь лучший способ получить общий размер файла (работает для каталога и некаталога):

Изменить: обратите внимание, что это, вероятно, займет много времени. Не запускайте его в потоке пользовательского интерфейса.

  • Работает для Android и Java
  • Работает как для папок, так и для файлов
  • Проверяет нулевой указатель везде, где это необходимо
  • Игнорирует символическую ссылку aka shortcuts
  • Продукция готова!

После много исследований и изучения различных решений, предлагаемых здесь в StackOverflow. Наконец я решил написать собственное решение. Моя цель - иметь механизм без броска, потому что я не хочу сбой, если API не может получить размер папки. Этот метод не подходит для многопоточного сценария.

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

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

Наконец, моя реализация на основе рекурсии позволяет получить размер указанной директории. Обратите внимание на нулевую проверку для dir.listFiles(). Согласно javadoc существует вероятность того, что этот метод может вернуть null.

Некоторые кремы на торте, API, чтобы получить размер списка Файлы (возможно, все файлы и папки под root).

есть ли эффективный способ в java получить размер файла?

Ну, я попытался измерить его с помощью кода ниже:

для runs = 1 и итераций = 1 метод URL-адреса является самым быстрым в большинстве случаев с последующим каналом. Я запускаю это с некоторой паузой около 10 раз. Таким образом, в течение одного времени доступ, используя URL-адрес, это самый быстрый способ, который я могу придумать:

для прогонов = 5 и итераций = 50 рисунок рисуется по-разному.

файл должен кэшировать вызовы файловой системы, в то время как каналы и URL имеют некоторые накладные расходы.

бенчмарк, заданный GHad, измеряет множество других вещей (таких как отражение, создание экземпляров объектов и т. д. кроме того, чтобы получить длину. Если мы попытаемся избавиться от этих вещей, то за один звонок я получаю следующее время в микросекундах:

для 100 запусков и 10000 итераций я:

я запустил следующий измененный код, дающий в качестве аргумента имя файла 100MB.

глядя на результат, я думаю, что файл.length() действительно победитель.

порядок тестирования-это порядок вывода. Вы даже можете видеть, что время, затраченное на мою машину, варьировалось между казнями, но Файл.Length () когда не первый, и при первом доступе к диску выиграл.

когда я изменяю ваш код для использования файла, доступ к которому осуществляется по абсолютному пути вместо ресурса, я получаю другой результат (для 1 запуска, 1 итерации и файла 100,000 байт-раз для файла 10 байт идентичны 100,000 байт)

сумма длины: 33, за итерацию: 33.0

сумма каналов: 3626, за итерацию: 3626.0

сумма URL: 294, за итерацию: 294.0

в ответ на бенчмарк rgrig, время, необходимое для открытия / закрытия экземпляров FileChannel & RandomAccessFile также необходимо учитывать, так как эти классы откроют поток для чтения файла.

после изменения бенчмарка я получил эти результаты для 1 итерации в файле 85MB:

для 10000 итераций в одном файле:

Если все, что вам нужно, это размер файла, файл.length () - самый быстрый способ сделать это. Если вы планируете используйте файл для других целей, таких как чтение/запись, тогда RAF кажется лучшей ставкой. Просто не забудьте закрыть файловое соединение : -)

Я столкнулся с этой же проблемой. Мне нужно было получить размер файла и дату изменения 90,000 файлов в сетевом ресурсе. Используя Java и будучи максимально минималистичным, это займет очень много времени. (Мне нужно было получить URL-адрес из файла, а также путь к объекту. Так что он несколько разнился, но больше часа.) Затем я использовал собственный исполняемый файл Win32 и выполнил ту же задачу, просто сбросив путь к файлу, измененный и размер в консоль, и выполнил это из Java. Скорость было потрясающе. Собственный процесс и моя обработка строк для чтения данных могут обрабатывать более 1000 элементов в секунду.

Так что, хотя люди вниз оценили выше комментарий, это действительное решение и решили мою проблему. В моем случае я знал папки, которые мне нужны, размеры заранее, и я мог передать это в командной строке моему приложению win32. Я переходил от часов к обработке каталога к минутам.

проблема также казалась специфичной для Windows. OS X не имел та же проблема и может получить доступ к информации сетевого файла так же быстро, как ОС может это сделать.

обработка файлов Java в Windows ужасна. Доступ к локальному диску для файлов в порядке. Это были просто сетевые ресурсы, которые вызвали ужасную производительность. Windows может получить информацию о сетевом ресурсе и рассчитать общий размер менее чем за минуту.

если вы хотите размер файла нескольких файлов в каталоге, используйте Files.walkFileTree . Вы можете получить размер из BasicFileAttributes что вы получите.

это намного быстрее, чем вызов .length() в результате File.listFiles() или через Files.size() в результате Files.newDirectoryStream() . В моих тестовых случаях это было примерно в 100 раз быстрее.

на самом деле, я думаю, что "LS" может быть быстрее. Есть определенно некоторые проблемы в Java, связанные с получением информации о файле. К сожалению, нет эквивалентного безопасного метода рекурсивных ls для Windows. (УМК.exe DIR / S может запутаться и генерировать ошибки в бесконечных циклах)

на XP, доступ к серверу в локальной сети, мне требуется 5 секунд в Windows, чтобы получить количество файлов в папке (33,000) и общий размер.

когда я повторяю рекурсивно через это на Java это занимает у меня более 5 минут. Я начал измерять время, необходимое для создания файла.length (), file.lastModified () и файл.toURI() и я обнаружил, что 99% моего времени занимают эти 3 звонка. 3 звонка, которые мне действительно нужно сделать.

разница для 1000 файлов составляет 15 мс локально против 1800 МС на сервере. Сканирование пути сервера в Java смехотворно медленно. Если родная ОС может быть быстрой при сканировании той же папки, почему Java не может?

как более полный тест, я использовал WineMerge на XP для сравнения измененной даты и размера файлов на сервере против файлов локально. Это повторялось по всему дереву каталогов из 33 000 файлов в каждой папке. Общее время, 7 секунд. java: более 5 минут.

таким образом, исходное утверждение и вопрос из OP истинны и действительны. Это менее заметно при работе с локальной файловой системой. Выполнение локального сравнения папки с 33 000 элементов занимает 3 секунды в WinMerge и занимает 32 секунд локально в Java. Опять же, java против native-это замедление 10x в этих рудиментарных тестах.

Java 1.6.0_22 (последний), Gigabit LAN и сетевые подключения, ping меньше 1 мс (оба в одном коммутаторе)

из эталона GHad, есть несколько вопросов, которые люди упомянули:

1>Как BalusC отметил: поток.в этом случае available() течет.

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

Итак, 1st, чтобы удалить URL-адрес этого подхода.

2>Как упоминал Стюарт - заказ тестового запуска также делает разницу в кэше, поэтому выньте это, выполнив тест отдельно.

Читайте также: