Есть ли лучшая альтернатива методу File.listFiles ()? - PullRequest
0 голосов
/ 29 апреля 2018

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

File diretory = <dir_path>;
File[] listFiles = directory.listFiles();
for (int i = 0; i < listFiles.length; i++) {
    String fileName = file.getName();
    String filePath = file.getAbsolutePath();
    long fileLen = file.length();
    long filelastModified = file.getLastModified();
    ...
}

Мой каталог может содержать 1000 файлов. Поскольку операции ввода-вывода очень дороги, является ли это наиболее оптимальным способом выполнения моей работы?

Ответы [ 4 ]

0 голосов
/ 29 апреля 2018

С Java 7 java.nio.file.DirectoryStream<Path> предлагает альтернативу с огромным приростом производительности.

import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
...
    private static void nioDir( String filePath, int maxFiles )
       throws IOException {
      int i = 1;
      Path dir = FileSystems.getDefault().getPath( filePath );
      DirectoryStream<Path> stream = Files.newDirectoryStream( dir );
      for (Path path : stream) {
        System.out.println( "" + i + ": " + path.getFileName() );
        if (++i > maxFiles) break;
      }
      stream.close();
    }
0 голосов
/ 29 апреля 2018

В вашем случае:

File[] listFiles = directory.listFiles();

создаст 1000 File объектов, но это не дорогие операции ввода-вывода, так как new File() не выполняет операции ввода-вывода при создании объектов как FileInputStream.
Но учтите, что вы все равно можете избежать создания всех объектов Files за один раз и сокращения потребляемой памяти за счет потоковой передачи файлов.
Files.newDirectoryStream(Path dir), который возвращает DirectoryStream<Path>, и Files.list(Path dir), который возвращает Stream<Path>, предоставляют способы достижения этого.
Вот пост, указывающий на некоторые различия между ними.

Таким образом, вы можете получить тот же результат с помощью java.nio API следующим образом:

Path directory = ...;
Files.newDirectoryStream(directory)
     .forEach(p -> {
         try {
            String fileName = p.getFileName().toString();
            String filePath = p.toAbsolutePath().toString();
            long fileLen =  Files.size(p);
            long filelastModified = Files.getLastModifiedTime(p).toMillis();
        } catch (IOException e) {
            // FIXME to handle
        }

     });

Редактировать для комментария:

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

В этом случае Files.walk() больше подходит, так как он рекурсивный.
Это очень близко к:

Path directory = ...;
Files.walk(directory)
     .forEach(p -> {
         try {
                // same code ....
         } catch (IOException e) {
             // FIXME to handle
         }

     });
0 голосов
/ 29 апреля 2018

Я бы использовал File.list (), а не listFiles (), он немного ближе к нативному API, меньше объектов File для создания авансом. Но это небольшой выигрыш.

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

Вы не сэкономите на размерах и дате, их нужно вызывать один раз для каждого, извините.

0 голосов
/ 29 апреля 2018

AFAIK, это близко к максимально эффективному в Java. Возможно, вам удастся выжать от 2 до 5 процентов, но обычно это не то улучшение производительности, которое стоит.

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

Я ожидаю, что операции с метаданными (length(), getLastModified() и так далее) будут использовать подавляющее большинство времени. Но стоит проверить профилирование вашего приложения.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...