OutOfMemory, когда файлы списка в каталоге

Когда я перечисляю файлы каталога с 300 000 файлов с Java, происходит нехватка памяти.

String[] fileNames = file.list();

То, что я хочу, это способ, который может перечислить все файлы каталога постепенно, независимо от того, сколько файлов в этом конкретном каталоге и не будет иметь проблемы с "нехваткой памяти" с максимальным размером кучи по умолчанию 64 МБ.

У меня есть Google некоторое время, и я не могу найти такой путь в чистой Java.
Пожалуйста, помогите мне!

Примечание. JNI - это возможное решение, но я ненавижу JNI.

Ответ 1

Я знаю, что вы сказали "с пределом кучи по умолчанию 64M", но давайте посмотрим на факты - вы хотите удержать (потенциально) большое количество элементов в памяти, используя механизмы, предоставленные вам Java. Итак, если нет какой-то серьезной причины, по которой вы не можете, я бы сказал, что увеличение кучи - это путь.

Вот ссылка на одно и то же обсуждение в JavaRanch: http://www.coderanch.com/t/381939/Java-General/java/iterate-over-files-directory

Изменить, в ответ на комментарий: причина, по которой я сказал, что он хочет хранить большое количество элементов в памяти, состоит в том, что это единственный механизм, который Java предоставляет для перечисления каталога без использования собственного интерфейса или механизмы, специфичные для платформы (и OP сказал, что ему нужна "чистая Java" ).

Ответ 2

Единственное возможное решение для вас - это Java7, а затем вы можете использовать итератор.

final Path p = FileSystems.getDefault().getPath("Yourpath");
Files.walk(p).forEach(filePath -> {
        if (Files.isRegularFile(filePath)) {
            //Do something with filePath
        }
});

Ответ 3

Вам здесь немного не повезло. По крайней мере, потребуется создать 300k строк. Средняя длина 8-10 char и 2 байта за char составляет минимум 6 Мб. Добавьте служебную нагрузку указателя объекта на строку (8 байт), и вы запуститесь в свой предел памяти.

Если вы абсолютно должны иметь такое количество файлов в одном каталоге, которое я бы не рекомендовал, так как ваша файловая система будет иметь проблемы, лучше всего запустить собственный процесс (не JNI) через Runtime.exec. Имейте в виду, что вы привяжете себя к ОС (ls vs dir). Вы сможете получить список файлов в виде одной большой строки и нести ответственность за последующую обработку его в то, что вы хотите.

Надеюсь, что это поможет.

Ответ 4

Наличие 300 000 файлов в каталоге не является хорошей идеей - файловые системы AFAIK не очень хороши в том, что у многих подузлов есть только один node. Интересный вопрос, тем не менее.

РЕДАКТИРОВАТЬ: ПОСЛЕДУЮЩИЕ НЕ ПОМОГАЕТ, см. комментарии.

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

        new File("c:/").listFiles( new FileFilter() {
            @Override   public boolean accept(File pathname) {
                processFile();
                return false;
            }
        });

Ответ 5

Если вы можете написать свой код в Java 7 или выше, то подходящим вариантом является следующий.

Files.newDirectoryStream(Path dir)

Здесь - это java-документ для API.

Надеюсь, что это поможет.