«1. Введение

Эта короткая статья представляет OpenCSV 4, фантастическую библиотеку для записи, чтения, сериализации, десериализации и/или анализа файлов .csv! Ниже мы рассмотрим несколько примеров, демонстрирующих, как настроить и использовать OpenCSV 4 для ваших целей.

2. Настройка

Вот как добавить OpenCSV в ваш проект с помощью зависимости pom.xml:

<dependency>
    <groupId>com.opencsv</groupId>
    <artifactId>opencsv</artifactId>
    <version>4.1</version>
</dependency>

.jars для OpenCSV можно найти на официальном сайте или через быстрый поиск в репозитории Maven.

Наш файл .csv будет очень простым, мы сократим его до двух столбцов и четырех строк:

colA, ColB
A, B
C, D
G, G
G, F

3. Bean или Not to Bean

После добавления OpenCSV в ваш pom.xml, мы можем реализовать методы обработки CSV двумя удобными способами:

  1. using the handy CSVReader and CSVWriter objects (for simpler operations) or
  2. using CsvToBean to convert .csv files into beans (which are implemented as annotated plain-old-java-objects).

В этой статье мы остановимся на синхронных (или блокирующих) примерах, чтобы сосредоточиться на основах.

Помните, что синхронный метод предотвратит выполнение окружающего или последующего кода до тех пор, пока он не будет выполнен. Любая производственная среда, вероятно, будет использовать асинхронные или (неблокирующие) методы, которые позволят другим процессам или методам завершиться, пока завершается асинхронный метод.

Мы рассмотрим асинхронные примеры для OpenCSV в следующей статье.

3.1. CSVReader

CSVReader — с помощью предоставленных методов readAll() и readNext()! Давайте посмотрим, как синхронно использовать readAll():

public List<String[]> readAll(Reader reader) throws Exception {
    CSVReader csvReader = new CSVReader(reader);
    List<String[]> list = new ArrayList<>();
    list = csvReader.readAll();
    reader.close();
    csvReader.close();
    return list;
}

Затем мы можем вызвать этот метод, передав BufferedReader:

public String readAllExample() throws Exception {
    Reader reader = Files.newBufferedReader(Paths.get(
      ClassLoader.getSystemResource("csv/twoColumn.csv").toURI()));
    return CsvReaderExamples.readAll(reader).toString();
}

Аналогичным образом, мы можем абстрагироваться от readNext(), который считывает предоставленный файл . csv построчно:

public List<String[]> oneByOne(Reader reader) throws Exception {
    List<String[]> list = new ArrayList<>();
    CSVReader csvReader = new CSVReader(reader);
    String[] line;
    while ((line = csvReader.readNext()) != null) {
        list.add(line);
    }
    reader.close();
    csvReader.close();
    return list;
}

И мы можем вызвать этот метод здесь, передав BufferReader:

public String oneByOneExample() throws Exception {
    Reader reader = Files.newBufferedReader(Paths.get(
      ClassLoader.getSystemResource("csv/twoColumn.csv").toURI()));
    return CsvReaderExamples.oneByOne(reader).toString();
}

Для большей гибкости и возможностей конфигурации вы можете альтернативно использовать CSVReaderBuilder:

CSVParser parser = new CSVParserBuilder()
    .withSeparator(',')
    .withIgnoreQuotations(true)
    .build();

CSVReader csvReader = new CSVReaderBuilder(reader)
    .withSkipLines(0)
    .withCSVParser(parser)
    .build();

CSVReaderBuilder позволяет один, чтобы пропустить заголовки столбцов и установить правила синтаксического анализа через CSVParserBuilder.

Используя CSVParserBuilder, мы можем выбрать собственный разделитель столбцов, игнорировать или обрабатывать кавычки, указать, как мы будем обрабатывать нулевые поля и как интерпретировать экранированные символы. Для получения дополнительной информации об этих параметрах конфигурации обратитесь к официальной документации спецификации.

Как всегда, не забудьте закрыть все ваши программы чтения, чтобы предотвратить утечку памяти!

3.2. Аналогичным образом CSVWriter

CSVWriter предоставляет возможность записи в файл .csv целиком или построчно.

Давайте посмотрим, как выполнить построчную запись в .csv:

public String csvWriterOneByOne(List<String[]> stringArray, Path path) throws Exception {
    CSVWriter writer = new CSVWriter(new FileWriter(path.toString()));
    for (String[] array : stringArray) {
        writer.writeNext(array);
    }
    
    writer.close();
    return Helpers.readFile(path);
}

Теперь давайте укажем, где мы хотим сохранить этот файл, и вызовем метод, который мы только что написали:

public String csvWriterOneByOne() throws Exception{
    Path path = Paths.get(
      ClassLoader.getSystemResource("csv/writtenOneByOne.csv").toURI()); 
    return CsvWriterExamples.csvWriterOneByOne(Helpers.fourColumnCsvString(), path); 
}

~~ ~ Мы также можем написать наш .csv все сразу, передав массивы List of String, представляющие строки нашего .csv. :

public String csvWriterAll(List<String[]> stringArray, Path path) throws Exception {
     CSVWriter writer = new CSVWriter(new FileWriter(path.toString()));
     writer.writeAll(stringArray);
     writer.close();
     return Helpers.readFile(path);
}

А вот как мы это называем:

public String csvWriterAll() throws Exception {
    Path path = Paths.get(
      ClassLoader.getSystemResource("csv/writtenAll.csv").toURI()); 
    return CsvWriterExamples.csvWriterAll(Helpers.fourColumnCsvString(), path);
}

Вот оно!

3.3. Чтение на основе bean-компонентов

OpenCSV может сериализовать файлы .csv в предустановленные и повторно используемые схемы, реализованные в виде аннотированных Java-компонентов pojo. CsvToBean создается с использованием CsvToBeanBuilder. Начиная с OpenCSV 4, CsvToBeanBuilder является рекомендуемым способом работы с com.opencsv.bean.CsvToBean.

Вот простой bean-компонент, который мы можем использовать для сериализации нашего двухколоночного .csv из раздела 2.:

public class SimplePositionBean  {
    @CsvBindByPosition(position = 0)
    private String exampleColOne;

    @CsvBindByPosition(position = 1)
    private String exampleColTwo;

    // getters and setters
}

Каждый столбец в .csv-файле связан с полем в bean-компоненте. Сопоставления между заголовками столбцов .csv можно выполнять с помощью аннотаций @CsvBindByPosition или @CsvBindByName, которые определяют сопоставление по положению или совпадению строки заголовка соответственно.

Во-первых, давайте создадим суперкласс с именем CsvBean — это позволит нам повторно использовать и обобщать методы, которые мы создадим ниже:

public class CsvBean { }

Пример дочернего класса:

public class NamedColumnBean extends CsvBean {

    @CsvBindByName(column = "name")
    private String name;

    @CsvBindByName
    private int age;

    // getters and setters
}

Давайте абстрагируем синхронно возвращаемый список с использованием CsvToBean:

 public List<CsvBean> beanBuilderExample(Path path, Class clazz) throws Exception {
     CsvTransfer csvTransfer = new CsvTransfer();
     ColumnPositionMappingStrategy ms = new ColumnPositionMappingStrategy();
     ms.setType(clazz);

     Reader reader = Files.newBufferedReader(path);
     CsvToBean cb = new CsvToBeanBuilder(reader)
       .withType(clazz)
       .withMappingStrategy(ms)
       .build();

    csvTransfer.setCsvList(cb.parse());
    reader.close();
    return csvTransfer.getCsvList();
}

Мы передаем наш компонент (clazz) и устанавливаем его как ColumnPositionMappingStrategy. При этом мы связываем поля наших bean-компонентов с соответствующими столбцами наших строк .csv.

Мы можем вызвать это здесь, используя подкласс SimplePositionBean CsvBean, который мы написали выше:

public String simplePositionBeanExample() throws Exception {
    Path path = Paths.get(
      ClassLoader.getSystemResource("csv/twoColumn.csv").toURI()); 
    return BeanExamples.beanBuilderExample(path, SimplePositionBean.class).toString(); 
}

или здесь, используя NamedColumnBean — другой подкласс CsvBean:

public String namedColumnBeanExample() throws Exception {
    Path path = Paths.get(
      ClassLoader.getSystemResource("csv/namedColumn.csv").toURI()); 
    return BeanExamples.beanBuilderExample(path, NamedColumnBean.class).toString();
}

3.4. Запись на основе компонентов

Наконец, давайте посмотрим, как использовать класс StatefulBeanToCsv для записи в файл .csv:

public String writeCsvFromBean(Path path) throws Exception {
    Writer writer  = new FileWriter(path.toString());

    StatefulBeanToCsv sbc = new StatefulBeanToCsvBuilder(writer)
       .withSeparator(CSVWriter.DEFAULT_SEPARATOR)
       .build();

    List<CsvBean> list = new ArrayList<>();
    list.add(new WriteExampleBean("Test1", "sfdsf", "fdfd"));
    list.add(new WriteExampleBean("Test2", "ipso", "facto"));

    sbc.write(list);
    writer.close();
    return Helpers.readFile(path);
}

«

«Здесь мы указываем, как мы будем разграничивать наши данные, которые предоставляются в виде списка указанных объектов CsvBean.

public String writeCsvFromBeanExample() {
    Path path = Paths.get(
      ClassLoader.getSystemResource("csv/writtenBean.csv").toURI()); 
    return BeanExamples.writeCsvFromBean(path); 
}

Затем мы можем вызвать наш метод writeCsvFromBean() после передачи нужного пути к выходному файлу:

4. Заключение

Вот и все — примеры синхронного кода для OpenCSV с использованием bean-компонентов, CSVReader и CSVWriter. Ознакомьтесь с официальными документами здесь.