Univocity - Как вернуть один компонент в строку, используя стиль итератора?

Введение

Я создаю процесс для объединения нескольких больших отсортированных CSV-файлов. В настоящее время я изучаю возможность использования Univocity для этого. Способ, которым я настраиваю слияние, заключается в использовании bean-компонентов, которые реализуют сопоставимый интерфейс.

Данный

Упрощенный файл выглядит так:

id,data
1,aa
2,bb
3,cc

Компонент выглядит следующим образом (геттеры и сеттеры опущены):

public class Address implements Comparable<Address> {

    @Parsed
    private int id;
    @Parsed
    private String data;        

    @Override
    public int compareTo(Address o) {
        return Integer.compare(this.getId(), o.getId());
    }
}

Компаратор выглядит так:

public class AddressComparator implements Comparator<Address>{

    @Override
    public int compare(Address a, Address b) {
        if (a == null)
            throw new IllegalArgumentException("argument object a cannot be null");
        if (b == null)
            throw new IllegalArgumentException("argument object b cannot be null");
        return Integer.compare(a.getId(), b.getId());
    }
}

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

public class App {
    
    private static final String INPUT_1 = "src/test/input/address1.csv";
    private static final String INPUT_2 = "src/test/input/address2.csv";
    private static final String INPUT_3 = "src/test/input/address3.csv";
    
    public static void main(String[] args) throws FileNotFoundException {       
        BeanListProcessor<Address> rowProcessor = new BeanListProcessor<Address>(Address.class);
        CsvParserSettings parserSettings = new CsvParserSettings();
        parserSettings.setRowProcessor(rowProcessor);       
        parserSettings.setHeaderExtractionEnabled(true);
        CsvParser parser = new CsvParser(parserSettings);       
        
        List<FileReader> readers = new ArrayList<>();
        readers.add(new FileReader(new File(INPUT_1)));
        readers.add(new FileReader(new File(INPUT_2)));
        readers.add(new FileReader(new File(INPUT_3)));
        
        // This parses all rows, but I am only interested in getting 1 row as a bean.
        for (FileReader fileReader : readers) {
            parser.parse(fileReader);
            List<Address> beans = rowProcessor.getBeans();
            for (Address address : beans) {
                System.out.println(address.toString());
            }           
        }
        
        // want to have a map with the reader and the first bean object
        // Map<FileReader, Address> topRecordofReader = new HashMap<>();
        Map<FileReader, String[]> topRecordofReader = new HashMap<>();
        for (FileReader reader : readers) {
            parser.beginParsing(reader);
            String[] row;
            while ((row = parser.parseNext()) != null) {
               System.out.println(row[0]); 
               System.out.println(row[1]); 
               topRecordofReader.put(reader, row);
               // all done, only want to get first row
               break;        
            }
        }       
    }   
}

Вопрос

Учитывая приведенный выше пример, как мне выполнить синтаксический анализ таким образом, чтобы он выполнял итерацию по каждой строке и возвращал bean-компонент для каждой строки вместо анализа всего файла?

Я ищу что-то вроде этого (этот неработающий код просто указывает, какое решение я ищу):

for (FileReader fileReader : readers) {
            parser.beginParsing(fileReader);            
            Address bean = null;
            while (bean = parser.parseNextRecord() != null) {
                topRecordofReader.put(fileReader, bean);
            }                       
        }

person Sander_M    schedule 27.06.2016    source источник


Ответы (1)


Есть два подхода к итеративному чтению вместо загрузки всего в память, первый — использовать BeanProcessor вместо BeanListProcessor:

settings.setRowProcessor(new BeanProcessor<Address>(Address.class) {
        @Override
        public void beanProcessed(Address address, ParsingContext context) {
            // your code to process the each parsed object here!
        }

Для итеративного чтения компонентов без обратного вызова (и для выполнения некоторых других распространенных процессов) мы создали CsvRoutines (наследуется от AbstractRoutines — дополнительные примеры здесь):

    File input = new File("/path/to/your.csv")

    CsvParserSettings parserSettings = new CsvParserSettings();
    //...configure the parser

    // You can also use TSV and Fixed-width routines
    CsvRoutines routines = new CsvRoutines(parserSettings); 
    for (Address address : routines.iterate(Address.class, input, "UTF-8")) {
        //process your bean
    }

Надеюсь это поможет!

person Jeronimo Backes    schedule 27.06.2016
comment
Отвечает (поправьте меня, если я ошибаюсь) ведущий разработчик Univocity: «Мне нравится это сообщество». Большое спасибо за этот подробный и отличный ответ. Я все чаще использую парсеры Univocity в своих проектах, потому что их очень легко настроить. Я с нетерпением жду начала кодирования моего небольшого проекта быстрого слияния больших файлов с использованием Univocity. - person Sander_M; 28.06.2016
comment
У вас отличный синтаксический анализатор, но вы должны добавить приведенный выше пример КАК получить java-бин из справочного документа, где вы описываете, как создать java-бин: univocity.com/pages/java_beans.html (Кроме того, то, что вы называете java-бинами, на самом деле является POJO...) - person Nick; 05.11.2018
comment
@nick Страница, на которую вы ссылаетесь, посвящена аннотациям, которые могут использоваться всеми парсерами, которые мы делаем, а не только парсерами однозначности. Пример, показывающий, как перебирать bean-компоненты, представлен здесь: univocity.com/pages/univocity_parsers_routines.html< /а>. Кроме того, POJO — это объект Java, который не требует использования определенных аннотаций для совместимости с фреймворком. - person Jeronimo Backes; 05.11.2018