как узнать размер файла и каталога в Java без создания объекта?
Моя проблема в том, что в моем случае размер файлов и каталогов слишком велик (в сотнях мб). Когда я пытаюсь узнать размер, используя приведенный выше код (например, создавая файловый объект), моя программа становится настолько требовательной к ресурсам, что снижает производительность.
Есть ли способ узнать размер файла без создания объекта?
Я использую для файлов File file1 = new file (fileName); длинный размер = file1.length ();
А для каталога File dir1 = new file (dirPath); длинный размер = fileUtils.sizeOfDirectiry (dir1);
У меня есть один параметр, который позволяет вычислять размер. Если параметр false, то все идет гладко. Если false, программа тормозит или зависает. Я рассчитываю размер 4 каталогов и 2 файлов базы данных.
6 ответов
Если это ваша ситуация, я бы предложил реструктурировать каталог, чтобы иметь какую-то иерархию, которая обеспечит небольшое количество файлов в каждом подкаталоге.
Я думаю, что вам нужно прочитать метаданные файла. Прочтите это руководство для получения дополнительной информации. Это может быть решение, которое вы ищете: http://download.oracle.com/javase/tutorial/essential/io /fileAttr.html
У нас была аналогичная проблема производительности с File.listFiles () в каталогах с большим количеством файлов.
Наша установка представляла собой одну папку с 10 подпапками по 10 000 файлов в каждой. Папка находилась в общей сетевой папке, а не на машине, на которой выполнялся тест.
Мы использовали FileFilter, чтобы принимать только файлы с известными расширениями или каталогом, чтобы мы могли обратиться к каталогам.
Профилирование показало, что около 70% времени было потрачено на вызов File.isDirectory (который, как я предполагаю, вызывает Apache). Было два вызова isDirectory для каждого файла (один в фильтре и один на этапе обработки файла).
File.isDirectory был медленным, потому что ему приходилось попадать в общий сетевой ресурс для каждого файла.
Изменение порядка проверки в фильтре для проверки действительного имени перед действительным каталогом сэкономило много времени, но нам все равно нужно было вызвать isDirectory для рекурсивного поиска.
Мое решение заключалось в том, чтобы реализовать версию listFiles в собственном коде, которая возвращала бы структуру данных, содержащую все метаданные о файле, а не только имя файла, как это делает File.
Это устранило проблему производительности, но добавило проблему обслуживания, связанную с необходимостью поддержки нативного кода разработчиками Java (к счастью, мы поддерживали только одну ОС).
Если вы хотите получить размер всех файлов в каталоге, ОС должна прочитать каталог, а затем найти каждый файл, чтобы узнать его размер. Каждый доступ занимает около 10 мс (потому что это типичное время поиска для жесткого диска). Таким образом, если у вас есть 100 000 файлов, вам потребуется около 17 минут, чтобы получить все их размеры.
Кстати: размер каждого файла не имеет значения, потому что он фактически не читает файл. Только запись файла, имеющая размер.
РЕДАКТИРОВАТЬ: Например, если я попытаюсь получить размеры большого каталога. Сначала это происходит медленно, но после кэширования данных становится намного быстрее.
Причина, по которой поиск выполняется так быстро, в первый раз, заключается в том, что все файлы были установлены сразу, и большая часть информации постоянно доступна на диске. Как только информация находится в памяти, считывание информации о файле практически мгновенно.
Время FileUtils.sizeOfDirectory («/ usr») занимает менее 8,7 секунд. Это относительно медленно по сравнению со временем, которое требуется du, но он обрабатывает около 30К файлов в секунду.
Файловые объекты очень легкие. Либо с вашим кодом что-то не так, либо проблема не в файловых объектах, а в доступе HD, необходимом для получения размера файла. Если вы сделаете это для большого количества файлов (скажем, десятков тысяч), то жесткий диск будет выполнять множество поисков, что в значительной степени является самой медленной операцией, возможной на современном ПК (на несколько порядки величины).
Как получить размер объекта в Java
Краткое и практическое руководство по получению размера объекта в Java.
1. Обзор
В отличие от C/C++, где мы можем использовать метод sizeof () для получения размера объекта в байтах, в Java нет истинного эквивалента такого метода.
В этой статье мы продемонстрируем, как мы все еще можем получить размер конкретного объекта.
2. Потребление памяти в Java
2.1. Объекты, ссылки и классы-оболочки
Ссылки имеют типичный размер 4 байта на 32-разрядных платформах и на 64-разрядных платформах с границей кучи менее 32 ГБ ( -Xmx32G ) и 8 байт для этой границы выше 32 ГБ.
Это означает, что 64-разрядной JVM обычно требуется на 30-50% больше места в куче.
3. Оценка Размера Объекта С Помощью Контрольно-Измерительных Приборов
Как мы могли видеть в документации Javadoc, метод обеспечивает “аппроксимацию для конкретной реализации” размера указанного объекта. Примечательно, что существует потенциальное включение накладных расходов в размер, и значения могут отличаться во время одного вызова JVM.
3.1. Создание Агента Инструментирования
Давайте теперь создадим класс Агент инструментирования :
Прежде чем мы создадим JAR для этого агента, нам нужно убедиться, что в него включен простой метафайл MANIFEST.MF :
Теперь мы можем создать банку агента с включенным файлом MANIFEST.MF. Один из способов-через командную строку:
3.2. Пример Класса
Давайте посмотрим на это в действии, создав класс с образцами объектов, которые будут использовать наш класс агента:
Чтобы это сработало, нам нужно включить опцию – javaagent с путем к JAR агента при запуске нашего приложения :
Результаты запуска нашего класса покажут нам предполагаемые размеры объектов:
4. Заключение
В этой статье мы описали, как память используется определенными типами в Java, как JVM хранит данные и подчеркивали вещи, которые могут повлиять на общее потребление памяти. Затем мы продемонстрировали, как мы можем на практике получить расчетный размер объектов Java.
java получить размер файла эффективно
в то время как googling, я вижу, что с помощью java.io.File#length() может быть медленным. FileChannel есть size() метод, который также доступен.
есть ли эффективный способ в java получить размер файла?
9 ответов
Ну, я попытался измерить его с помощью кода ниже:
для runs = 1 и итераций = 1 метод URL-адреса является самым быстрым в большинстве случаев с последующим каналом. Я запускаю это с некоторой паузой около 10 раз. Таким образом, в течение одного времени доступ, используя URL-адрес, это самый быстрый способ, который я могу придумать:
для прогонов = 5 и итераций = 50 рисунок рисуется по-разному.
файл должен кэшировать вызовы файловой системы, в то время как каналы и URL имеют некоторые накладные расходы.
бенчмарк, заданный GHad, измеряет множество других вещей (таких как отражение, создание экземпляров объектов и т. д. кроме того, чтобы получить длину. Если мы попытаемся избавиться от этих вещей, то за один звонок я получаю следующее время в микросекундах:
для 100 запусков и 10000 итераций я:
я запустил следующий измененный код, дающий в качестве аргумента имя файла 100MB.
все тестовые случаи в этом сообщении имеют недостатки, поскольку они обращаются к одному и тому же файлу для каждого проверенного метода. Так что кэширование диска пинков на тесты 2 и 3 воспользоваться. Чтобы доказать свою точку зрения, я взял тестовый пример, предоставленный GHAD, и изменил порядок перечисления, и ниже приведены результаты.
глядя на результат, я думаю, что файл.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 итераций в одном файле:
Я столкнулся с этой же проблемой. Мне нужно было получить размер файла и дату изменения 90,000 файлов в сетевом ресурсе. Используя Java и будучи максимально минималистичным, это займет очень много времени. (Мне нужно было получить URL-адрес из файла, а также путь к объекту. Так что он несколько разнился, но больше часа.) Затем я использовал собственный исполняемый файл Win32 и выполнил ту же задачу, просто сбросив путь к файлу, измененный и размер в консоль, и выполнил это из Java. Скорость было потрясающе. Собственный процесс и моя обработка строк для чтения данных могут обрабатывать более 1000 элементов в секунду.
Так что, хотя люди вниз оценили выше комментарий, это действительное решение и решили мою проблему. В моем случае я знал папки, которые мне нужны, размеры заранее, и я мог передать это в командной строке моему приложению win32. Я переходил от часов к обработке каталога к минутам.
проблема также казалась специфичной для Windows. OS X не имел та же проблема и может получить доступ к информации сетевого файла так же быстро, как ОС может это сделать.
обработка файлов Java в Windows ужасна. Доступ к локальному диску для файлов в порядке. Это были просто сетевые ресурсы, которые вызвали ужасную производительность. Windows может получить информацию о сетевом ресурсе и рассчитать общий размер менее чем за минуту.
на самом деле, я думаю, что «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-адрес этого подхода.
Теперь начать тест:
когда Первый канал работает в одиночку:
когда длина один бег в одиночку:
таким образом, похоже, что длина один победитель здесь:
Как узнать размер файла java
— Привет, Амиго. Давно не виделись.
— Привет, Билаабо. О чем будешь рассказывать?
— Сегодня я расскажу о работе с файлами. В Java есть специальный класс (File), с помощью которого можно управлять файлами на диске компьютера. Для того чтобы управлять содержимым файлов, есть другие классы: FileInputStream, FileOutputStream,…
— Интересно. А когда ты говоришь «управлять файлами», что ты имеешь в виду?
— Как раз сейчас и расскажу. Файлы можно создавать, удалять, переименовывать и еще много чего. В практически все классы, которые работают (читают, пишут, изменяют) с содержимым файла, можно передавать объект класса File. Пример:
| Можно сразу передавать имя файла в FileInputStream |
|---|
| FileInputStream input = new FileInputStream( «c:/path/a.txt» ); |
| А можно отдельно создать объект-файл, а потом передать его в FileInputStream |
| File file = new File( «c:/path/a.txt» ); FileInputStream input = new FileInputStream( file ); |
— Но во втором случае длиннее же получается. Так и не понял – зачем эти файлы нужны.
— Для этого конкретного случая – да. Это не пример, как надо делать, а скорее – как можно.
Но вот представь, что тебе нужно вывести на экран список всех файлов, которые находятся в определенной директории (папке). Вот как это можно сделать с помощью файлов:
— listFiles() – это метод, который возвращает список файлов в папке с именем «c:/path/»?
— Да. Хотя программисты обычно говорят «директория» или «каталог». Название «папка» стало употребляться совсем недавно, но, в принципе, они все верные, и ты можешь говорить, как тебе удобнее.
— Ок. А getName() что делает? Выдает имя файла? И какое именно имя? Полное вместе с путем или только имя самого файла?
— Только имя самого файла. Для полного есть file.getAbsolutePath()
— А какие еще методы есть у класса File?
— Ничего себе! А не маленький такой список получился. Да и вроде, можно довольно много сделать с помощью него: создавать, удалять файлы, переименовывать,…
А чтобы получить директорию текущего файла, надо вызвать getParent()?
— Ага, но он вернет не объект-файл, а строку – путь к файлу. Фактически у класса File почти все методы дублированы: одна версия возвращает String, вторая File. Вот смотри:
| File file = new File( «c:/path/a.txt» ); String directory = file.getParent(); |
| File file = new File( «c:/path/a.txt» ); File directory = file.getParentFile(); |
Если у тебя есть строка с путем к файлу, а надо объект File, то воспользуйся конструктором. Если же наоборот – есть объект File, а нужна строка – используй getAbsolutePath(). Пример:
— Отлично. Тогда вот тебе маленькое задание – выведи имена всех файлов, которые есть в той же директории, что и текущий файл.
— Нет ничего проще, вот, смотри:
| Код | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| //какой-то текущий файл File originalFile = new File(«c:/path/dir2/a.txt»); — А, то! Немного путает, что и для файла и для директории используется один и тот же класс – File. Как то это не очень логично, мне кажется. — Так исторически сложилось. Раньше директория была специальным «пустым» файлом на диске. Сейчас уже, конечно, многое изменилось, но не везде. У меня на сегодня все. — Спасибо, за отличную лекцию, Билаабо. 2. Задачи на File— Привет, Амиго! Я придумал тебе пару интересных задач. Решать их можно только в Intellij IDEA. Вот, смотри, какие интересные условия…
|






