Java 8: список файлов из нескольких путей - PullRequest
0 голосов
/ 11 июня 2018

Как искать файлы по нескольким путям в Java 8. Это не дочерние / дочерние каталоги.Например, если я хочу искать файлы json по пути, у меня есть:

try (Stream<Path> stream = Files.find(Paths.get(path), Integer.MAX_VALUE, (p, attrs) -> attrs.isRegularFile() && p.toString().endsWith(".json"))) {
  stream.map((p) -> p.name).forEach(System.out::println);
}

Есть ли лучший способ поиска по нескольким путям?Или я должен запустить один и тот же код для нескольких путей?

Ответы [ 2 ]

0 голосов
/ 11 июня 2018

Вот для чего flatMap.

Если у вас есть коллекция Path экземпляров в path, вы можете использовать

paths.stream()
     .flatMap(path -> {
         try { return Files.find(path, Integer.MAX_VALUE,
            (p, attrs) -> attrs.isRegularFile() && p.toString().endsWith(".json")); }
         catch (IOException ex) { throw new UncheckedIOException(ex); }
     })
     .forEach(System.out::println);

Это немного неуклюже из-зак тому, что мы имеем дело с проверенным IOException, заявленным find здесь.Возврат его в UncheckedIOException является самым простым выбором, поскольку именно так поступит поток, возвращаемый find, если возникнет проблема ввода-вывода при обработке потока.Сравните с документацию find

Если при обращении к каталогу после возврата из этого метода выбрасывается IOException, он переносится вUncheckedIOException, который будет выброшен из метода, вызвавшего доступ.

Таким образом, выполнение того же в нашей функции упрощает обработку ошибок вызывающей стороны, так как она простодолжен обрабатывать UncheckedIOException с.

Здесь нет способа использовать try(…), но именно поэтому flatMap снимет с нас это бремя.Как его документация гласит:

Каждый сопоставленный поток закрыт после помещения его содержимого в этот поток.

Итак, как только наша функция вернула подпоток, mplementation Stream сделает для нас правильную вещь.

Вы можете объединить произвольные операции потока вместо .forEach(System.out::println); для обработки всех элементов сплющенного потока, напримеродин поток.

Если ваша входная коллекция содержит экземпляры String вместо Path, вы можете просто добавить paths.stream().map(Paths::get) вместо paths.stream() к операции flatMap.

0 голосов
/ 11 июня 2018

Да, вы можете сделать это.Предполагая, что у вас есть пути в виде List из String объектов, вы можете сделать это следующим образом:

List<String> paths = ...;

paths.stream().map(path -> {
    try (Stream<Path> stream = Files.list(Paths.get(path))) {
        return stream.filter(p -> !p.toFile().isDirectory()).filter(p -> p.toString().endsWith(".json"))
                .map(Path::toString).collect(Collectors.joining("\n"));
    } catch (IOException e) {
        // Log your ERROR here.
        e.printStackTrace();
    }
    return "";
}).forEach(System.out::println);

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

paths.stream().map(path -> {
    try (Stream<Path> stream = Files.walk(Paths.get(path))) {
        return stream.filter(p -> !p.toFile().isDirectory()).filter(p -> p.toString().endsWith(".json"))
                .map(Path::toString).collect(Collectors.toList());
    } catch (IOException e) {
        e.printStackTrace();
    }
    return Collections.emptyList();
}).flatMap(List::stream).forEach(System.out::println);

Здесь вы получаете все .json имена файлов для каждого пути в List, а затем сжимаете их в плоский stream из String объектов перед печатью.,Обратите внимание, что в этом подходе используется дополнительный шаг flatMap.

...