Как узнать размер файла и каталога в Java без создания объекта? - PullRequest
3 голосов
/ 02 мая 2011

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

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

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

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

и для каталога: Файл dir1 = новый файл (dirPath); long size = fileUtils.sizeOfDirectiry (dir1);

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

Ответы [ 6 ]

4 голосов
/ 02 мая 2011

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

3 голосов
/ 02 мая 2011

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

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

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

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


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

$ time du -s /usr
2911000 /usr

real    0m33.532s
user    0m0.880s
sys 0m5.190s

$ time du -s /usr
2911000 /usr

real    0m1.181s
user    0m0.300s
sys 0m0.840s

$ find /usr | wc -l
259934

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

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

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

2 голосов
/ 02 мая 2011

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

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

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

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

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

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

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

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

1 голос
/ 09 мая 2011

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

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

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

1 голос
/ 02 мая 2011

Я думаю, что вам нужно прочитать метаданные файла.Прочитайте этот учебник для получения дополнительной информации.Это может быть решение, которое вы ищете: http://download.oracle.com/javase/tutorial/essential/io/fileAttr.html

0 голосов
/ 02 мая 2011

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

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

...