Как обрабатывать фрагменты файла с помощью java.util.stream

2

Чтобы получить familiar с потоком api, я попытался закодировать довольно простой шаблон.

Проблема: Наличие текстового файла, содержащего не вложенные блоки текста. Все блоки идентифицируются с помощью start/endpatterns (например, <start> и <stop>). Содержимое блока не является синтаксически различимым от шума между блоками, поэтому невозможно работать с простыми (безгосударственными) lambdas.

Я просто смог реализовать что-то уродливое, как:
Files.lines(path).collect(new MySequentialParseAndProsessEachLineCollector<>());
Честно говоря, это не то, что я хочу.

Я ищу картографа что-то вроде:
Files.lines(path).map(MyMapAllLinesOfBlockToBuckets()).parallelStream().collect(new MyProcessOneBucketCollector<>());

есть ли хороший способ извлечь куски данных из потока java 8, кажется, содержит скелет решения. К несчастью, я должен быть безупречным, чтобы перевести это на мою проблему.; -)

Любые подсказки?

Теги:
java-8
java-stream
parallel-processing

1 ответ

2

Вот решение, которое можно использовать для преобразования Stream<String>, каждого элемента, представляющего строку, в Stream<List<String>>, каждый элемент, представляющий фрагмент, найденный с использованием указанного разделителя:

public class ChunkSpliterator implements Spliterator<List<String>> {
    private final Spliterator<String> source;
    private final Predicate<String> start, end;
    private final Consumer<String> getChunk;
    private List<String> current;

    ChunkSpliterator(Spliterator<String> lineSpliterator,
        Predicate<String> chunkStart, Predicate<String> chunkEnd) {
        source=lineSpliterator;
        start=chunkStart;
        end=chunkEnd;
        getChunk=s -> {
            if(current!=null) current.add(s);
            else if(start.test(s)) current=new ArrayList<>();
        };
    }
    public boolean tryAdvance(Consumer<? super List<String>> action) {
        while(current==null || current.isEmpty()
                            || !end.test(current.get(current.size()-1)))
            if(!source.tryAdvance(getChunk)) return false;
        current.remove(current.size()-1);
        action.accept(current);
        current=null;
        return true;
    }
    public Spliterator<List<String>> trySplit() {
        return null;
    }
    public long estimateSize() {
        return Long.MAX_VALUE;
    }
    public int characteristics() {
        return ORDERED|NONNULL;
    }

    public static Stream<List<String>> toChunks(Stream<String> lines,
        Predicate<String> chunkStart, Predicate<String> chunkEnd,
        boolean parallel) {

        return StreamSupport.stream(
            new ChunkSpliterator(lines.spliterator(), chunkStart, chunkEnd),
            parallel);
    }
}

Строки, соответствующие предикатам, не включаются в кусок; было бы легко изменить это поведение, если это необходимо.

Его можно использовать следующим образом:

ChunkSpliterator.toChunks( Files.lines(Paths.get(myFile)),
    Pattern.compile("^<start>$").asPredicate(),
    Pattern.compile("^<stop>$").asPredicate(),
    true )
   .collect(new MyProcessOneBucketCollector<>())

Шаблоны указываются как ^word$, чтобы требовать, чтобы вся строка состояла только из слова; без этих якорей строки, содержащие шаблон, могут начинаться и заканчиваться куском. Характер потока источника не позволяет parallelism при создании кусков, поэтому при цепочке с немедленной операцией сбора данных parallelism для всей операции довольно ограничен. Это зависит от MyProcessOneBucketCollector, если вообще может быть любой parallelism.

Если ваш конечный результат не зависит от порядка вхождений ведер в исходном файле, настоятельно рекомендуется, чтобы ваш коллекционер сам считал UNORDERED или вы введете unordered() в цепочках методов потоков до collect.

  • 0
    ВАУ, это выглядит великолепно.
  • 0
    Для лучшего понимания вопроса о параллелизме. Предполагая, что сегменты UNORDERED , но порядок строк в Списке имеет значение, как заставить параллельное выполнение сборщика? <br/> ´ChunkSpliterator.toChunks (...). unordered () .rallelStream (). collect (..) `???
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню