Super CSV – чтение и запись CSV-файлов в Java

Язык Java не предоставляет никакой встроенной поддержки для эффективной обработки CSV-файлов. Поэтому мы будем использоватьSuper CSV для чтения CSV-файлов и записи нового CSV-файла на Java.

1. Зависимости Maven

Начнем с перечисления зависимостей Maven, необходимых для использования Super CSV в нашем проекте.

 <dependencies><dependency><groupId>net.sf.supercsv</groupId><artifactId>super-csv</artifactId><version>2.4.0</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.4</version></dependency>

Если вы используете сборку Gradle, то используйте это.

'net.sf.supercsv:super-csv:2.4.0''org.slf4j:slf4j-api:1.7.4'

2. Основные классы

Давайте рассмотрим основные классы, которые нам необходимо знать при работе с Super CSV для чтения или записи CSV-файлов.

2.1. ICsvBeanReader и CsvBeanReader

ICsvBeanReader(интерфейс) и CsvBeanReader(реализующий класс) используются для чтения CSV-файлов. Он читает CSV-файл, создавая экземпляр bean-компонента для каждой строки и отображая каждый столбец в поле bean-компонента.

Bean для заполнения может быть либо классом, либо интерфейсом. Если используется класс, он должен быть допустимым Java bean, т. е. он должен иметь конструктор без аргументов по умолчанию и методы getter/setter. Интерфейс также может использоваться, если он определяет getters/setters — будет создан прокси-объект, реализующий интерфейс.

2.2. ICsvBeanWriter и CsvBeanWriter

ICsvBeanWriter(интерфейс) и CsvBeanWriter(реализующий класс) используются для записи CSV-файлов. Он записывает CSV-файл, сопоставляя каждое поле в компоненте со столбцом в CSV-файле(используя предоставленное сопоставление имен).

2.3. ЯчейкаПроцессора

Экземпляры CellProcessor используются для чтения значения из CSV-файла и его обработки перед установкой в классе/интерфейсе Java Bean. Например, мы хотим преобразовать значение в объект Date или даже можем захотеть выполнить некоторую проверку значений с помощью регулярных выражений.

2.4.CSVPreference

Перед чтением или записью CSV-файлов необходимо предоставить читателю/писателю некоторые настройки. По сути, это означает, что вы устанавливаете конфигурацию, связанную с разделителями, в CSV-файле. Например, CsvPreference.STANDARD_PREFERENCE означает:

Quote character = "Delimiter character = ,End of line symbols = \r\n

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

private static final CsvPreference PIPE_DELIMITED = new CsvPreference.Builder('"', '|', "\n").build();

3. Чтение CSV-файла

Теперь давайте рассмотрим пример чтения CSV-файла с использованием описанных выше классов. Я прочитаю ниже приведенный data.csv:

 CustomerId,CustomerName,Страна,PIN-код,Email10001,Локеш,Индия,110001,abc@gmail.com10002,Джон,США,220002,def@gmail.com10003, Синий, Франция, 330003, ghi@gmail.com10004, Редди, Германия, 440004, abc@gmail.com10005, Кумар, Индия, 110001, def@gmail.com10006,Пол,США,220002,ghi@gmail.com10007,Гримм,Франция,330003,abc@gmail.com10008, WhoAmI, Германия, 440004, def@gmail.com10009, Бхарат, Индия, 110001, ghi@gmail.com10010,Роки,США,220002,abc@gmail.com10011,Воэлла,Франция,330003,def@gmail.com10012, Грубер, Германия, 440004, ghi@gmail.com10013,Сатти,Индия,110001,abc@gmail.com10014,Бин,США,220002,def@gmail.com10015, Криш, Франция, 330003, ghi@gmail.com

И мы заполним экземпляры Customer.java значениями из вышеуказанного файла.

public class Customer{private Integer CustomerId;private String CustomerName;private String Country;private Long PinCode;private String Email;//Setters, getters, constructors, toString()}

Теперь взгляните на CSV-файл, первая строка — это имена столбцов. Они должны точно совпадать с именами полей бина, а бин имеет соответствующие сеттеры, определенные для каждого поля.

Если заголовок не совпадает(или заголовок отсутствует), то мы можем просто определить собственный массив сопоставления имен. [Я закомментировал строку, но вы можете понять намек.]

import java.io.FileReader;import java.io.IOException;import org.supercsv.cellprocessor.Optional;import org.supercsv.cellprocessor.ParseInt;import org.supercsv.cellprocessor.ParseLong;import org.supercsv.cellprocessor.constraint.NotNull;import org.supercsv.cellprocessor.constraint.StrRegEx;import org.supercsv.cellprocessor.ift.CellProcessor;import org.supercsv.io.CsvBeanReader;import org.supercsv.io.ICsvBeanReader;import org.supercsv.prefs.CsvPreference;public class ReadCSVFileExample {static final String CSV_FILENAME = "data.csv";public static void main(String[] args) throws IOException{try(ICsvBeanReader beanReader = new CsvBeanReader(new FileReader(CSV_FILENAME), CsvPreference.STANDARD_PREFERENCE)){// the header elements are used to map the values to the beanfinal String[] headers = beanReader.getHeader(true);//final String[] headers = new String[]{"CustomerId","CustomerName","Country","PinCode","Email"};final CellProcessor[] processors = getProcessors();Customer customer;while((customer = beanReader.read(Customer.class, headers, processors)) != null) {System.out.println(customer);}}}/*** Sets up the processors used for the examples.*/private static CellProcessor[] getProcessors() {final String emailRegex = "[a-z0-9\\._]+@[a-z0-9\\.]+";StrRegEx.registerMessage(emailRegex, "must be a valid email address");final CellProcessor[] processors = new CellProcessor[] {new NotNull(new ParseInt()), // CustomerIdnew NotNull(), // CustomerNamenew NotNull(), // Countrynew Optional(new ParseLong()), // PinCodenew StrRegEx(emailRegex) // Email};return processors;}}

Вывод программы.

 Клиент [CustomerId=10001, CustomerName=Lokesh, Country=India, PIN-код=110001, Email=abc@gmail.com]Клиент [CustomerId=10002, CustomerName=John, Country=USA, PIN-код=220002, Email=def@gmail.com]Клиент [CustomerId=10003, CustomerName=Blue, Страна=Франция, PIN-код=330003, Электронная почта=ghi@gmail.com]//... Скоро

4. Частичное чтение CSV-файла

Частичное чтение позволяет нам игнорировать столбцы при чтении CSV-файлов, просто устанавливая соответствующие столбцы заголовков в null. Например, в приведенном ниже коде я решил НЕ читать столбец PinCode.

final String[] headers = new String[]{"CustomerId", "CustomerName", "Country", null, "Email"};

Теперь, если мы снова запустим указанную выше программу, значение пин-кода не будет заполнено, как показано в следующем выводе.

 Клиент [CustomerId=10001, CustomerName=Lokesh, Country=India, PIN-код=null, Email=abc@gmail.com]Клиент [CustomerId=10002, CustomerName=John, Country=USA, PIN-код=null, Email=def@gmail.com]Клиент [CustomerId=10003, CustomerName=Blue, Страна=Франция, PinCode=null, Email=ghi@gmail.com]//... Скоро

5. Чтение CSV-файла парами ключ-значение

Для чтения пар ключ-значение нам нужно использовать CsvMapReader. Он позволяет извлекать каждый столбец по имени из результирующей карты, хотя вам придется привести каждый столбец к соответствующему типу.

import java.io.FileReader;import java.io.IOException;import java.util.Map;import org.supercsv.cellprocessor.Optional;import org.supercsv.cellprocessor.ParseInt;import org.supercsv.cellprocessor.ParseLong;import org.supercsv.cellprocessor.constraint.NotNull;import org.supercsv.cellprocessor.constraint.StrRegEx;import org.supercsv.cellprocessor.ift.CellProcessor;import org.supercsv.io.CsvMapReader;import org.supercsv.io.ICsvMapReader;import org.supercsv.prefs.CsvPreference;public class ReadCSVFileInKeyValuePairs {static final String CSV_FILENAME = "data.csv";public static void main(String[] args) throws IOException{try(ICsvMapReader listReader = new CsvMapReader(new FileReader(CSV_FILENAME), CsvPreference.STANDARD_PREFERENCE)){//First Column is header namesfinal String[] headers = listReader.getHeader(true);final CellProcessor[] processors = getProcessors();Map<String, Object> fieldsInCurrentRow;while((fieldsInCurrentRow = listReader.read(headers, processors)) != null) {System.out.println(fieldsInCurrentRow);}}}/*** Sets up the processors used for the examples.*/private static CellProcessor[] getProcessors() {final String emailRegex = "[a-z0-9\\._]+@[a-z0-9\\.]+";StrRegEx.registerMessage(emailRegex, "must be a valid email address");final CellProcessor[] processors = new CellProcessor[] {new NotNull(new ParseInt()), // CustomerIdnew NotNull(), // CustomerNamenew NotNull(), // Countrynew Optional(new ParseLong()), // PinCodenew StrRegEx(emailRegex) // Email};return processors;}}

Вывод программы.

 {Страна=Индия, Идентификатор клиента=10001, Имя клиента=Локеш, Электронная почта=abc@gmail.com, ПИН-код=110001}{Страна=США, Идентификатор клиента=10002, Имя клиента=Джон, Электронная почта=def@gmail.com, ПИН-код=220002}{Страна=Франция, Идентификатор клиента=10003, Имя клиента=Blue, Электронная почта=ghi@gmail.com, ПИН-код=330003}//... Скоро

6. Чтение CSV-файла с произвольным количеством столбцов

Некоторые файлы CSV не соответствуют RFC4180 и имеют разное количество столбцов в каждой строке. Если у вас есть такой файл CSV, вам нужно будет использовать CsvListReader, так как это единственный ридер, поддерживающий его.

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

Давайте изменим файл data.csv и удалим из него некоторые данные случайным образом.

CustomerId,CustomerName,Country,PinCode,Email10001,Lokesh,India,110001,abc@gmail.com10002,John,USA10003,Blue,France,330003

Давайте прочитаем этот CSV-файл.

import java.io.FileReader;import java.io.IOException;import java.util.List;import org.supercsv.cellprocessor.Optional;import org.supercsv.cellprocessor.ParseInt;import org.supercsv.cellprocessor.ParseLong;import org.supercsv.cellprocessor.constraint.NotNull;import org.supercsv.cellprocessor.constraint.StrRegEx;import org.supercsv.cellprocessor.ift.CellProcessor;import org.supercsv.io.CsvListReader;import org.supercsv.io.ICsvListReader;import org.supercsv.prefs.CsvPreference;public class ReadCSVFileWithArbitraryNumberOfColumns {static final String CSV_FILENAME = "data.csv";public static void main(String[] args) throws IOException{try(ICsvListReader listReader = new CsvListReader(new FileReader(CSV_FILENAME), CsvPreference.STANDARD_PREFERENCE)){//First Column is header names- though we don't need it in runtime@SuppressWarnings("unused")final String[] headers = listReader.getHeader(true);CellProcessor[] processors = null;List<String> fieldsInCurrentRow;while((fieldsInCurrentRow = listReader.read()) != null) {if(fieldsInCurrentRow.size() == 5){processors = getFiveColumnProcessors();}else if(fieldsInCurrentRow.size() == 4) {processors = getFourColumnProcessors();}else if(fieldsInCurrentRow.size() == 3) {processors = getThreeColumnProcessors();}else{//Create more processors}final List<Object> formattedFields = listReader.executeProcessors(processors);System.out.println(String.format("rowNo=%s, customerList=%s", listReader.getRowNumber(), formattedFields));}}}private static CellProcessor[] getFiveColumnProcessors() {final String emailRegex = "[a-z0-9\\._]+@[a-z0-9\\.]+";StrRegEx.registerMessage(emailRegex, "must be a valid email address");final CellProcessor[] processors = new CellProcessor[] {new NotNull(new ParseInt()), // CustomerIdnew NotNull(), // CustomerNamenew NotNull(), // Countrynew Optional(new ParseLong()), // PinCodenew StrRegEx(emailRegex) // Email};return processors;}private static CellProcessor[] getFourColumnProcessors() {final CellProcessor[] processors = new CellProcessor[] {new NotNull(new ParseInt()), // CustomerIdnew NotNull(), // CustomerNamenew NotNull(), // Countrynew Optional(new ParseLong()) // PinCode};return processors;}private static CellProcessor[] getThreeColumnProcessors() {final CellProcessor[] processors = new CellProcessor[] {new NotNull(new ParseInt()), // CustomerIdnew NotNull(), // CustomerNamenew NotNull() //Country};return processors;}}

Вывод программы.

rowNo=2, customerList=[10001, Lokesh, India, 110001, abc@gmail.com]rowNo=3, customerList=[10002, John, USA]rowNo=4, customerList=[10003, Blue, France, 330003]

7. Запись в новый CSV-файл

Написание CSV-файла так же просто, как и чтение CSV-файла. Создайте экземпляр CsvBeanWriter, определите заголовки и процессоры и напишите бины. Он сгенерирует CSV-файл со значениями данных, заполненными из бинов.

import java.io.FileWriter;import java.io.IOException;import java.util.ArrayList;import java.util.List;import org.supercsv.cellprocessor.Optional;import org.supercsv.cellprocessor.ParseInt;import org.supercsv.cellprocessor.ParseLong;import org.supercsv.cellprocessor.constraint.NotNull;import org.supercsv.cellprocessor.constraint.StrRegEx;import org.supercsv.cellprocessor.ift.CellProcessor;import org.supercsv.io.CsvBeanWriter;import org.supercsv.io.ICsvBeanWriter;import org.supercsv.prefs.CsvPreference;public class WriteCSVFileExample{//Watch out for Exception in thread "main" java.lang.ExceptionInInitializerErrorprivate static List<Customer> customers = new ArrayList<Customer>();static{customers.add(new Customer(1, "Lokesh", "India", 12345L, "howtodoinjava@gmail.com"));customers.add(new Customer(2, "Mukesh", "India", 34234L, "mukesh@gmail.com"));customers.add(new Customer(3, "Paul", "USA", 52345345L, "paul@gmail.com"));}private static CellProcessor[] getProcessors(){final String emailRegex = "[a-z0-9\\._]+@[a-z0-9\\.]+";StrRegEx.registerMessage(emailRegex, "must be a valid email address");final CellProcessor[] processors = new CellProcessor[] {new NotNull(new ParseInt()), // CustomerIdnew NotNull(), // CustomerNamenew NotNull(), // Countrynew Optional(new ParseLong()), // PinCodenew StrRegEx(emailRegex) // Email};return processors;}public static void main(String[] args){ICsvBeanWriter beanWriter = null;try{beanWriter = new CsvBeanWriter(new FileWriter("temp.csv"), CsvPreference.STANDARD_PREFERENCE);final String[] header = new String[] { "CustomerId", "CustomerName", "Country", "PinCode" ,"Email" };final CellProcessor[] processors = getProcessors();// write the headerbeanWriter.writeHeader(header);// write the beans datafor(Customer c : customers) {beanWriter.write(c, header, processors);}} catch(IOException e) {e.printStackTrace();} finally {try {beanWriter.close();} catch(IOException e) {e.printStackTrace();}}}}

Вывод вышеуказанной программы будет записан в файл temp.csv, как показано ниже:

CustomerId,CustomerName,Country,PinCode,Email1,Lokesh,India,12345,howtodoinjava@gmail.com2,Mukesh,India,34234,mukesh@gmail.com3,Paul,USA,52345345,paul@gmail.com

Вот и все простые варианты использования и примеры использования Super CSV для чтения и записи CSV-файлов различными способами.

Пишите мне свои вопросы в комментариях.

Прокрутить вверх