Java language does not provide any native support for effectively handling CSV files. So we will use Super CSV to read CSV file and write a new CSV file in Java.
Read More : How to read and write CSV – OpenCSV tutorial
Table of Contents 1. Super CSV maven dependencies 2. Super CSV common classes 3. How to read a CSV file 4. How to partially read CSV file 5. How to read CSV file in key-value pairs 6. How to read CSV file with arbitrary number of columns 7. How to write a new CSV file
1. Super CSV maven dependencies
Let’s start by listing down maven dependencies needed to use Super CSV in our project.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd; <modelVersion>4.0.0</modelVersion> <groupId>SuperCSVExamples</groupId> <artifactId>SuperCSVExamples</artifactId> <version>0.0.1-SNAPSHOT</version> <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> </dependencies> <build> <sourceDirectory>src</sourceDirectory> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <source>1.7</source> <target>1.7</target> </configuration> </plugin> </plugins> </build> </project>
If you are using gradle build then use this.
'net.sf.supercsv:super-csv:2.4.0' 'org.slf4j:slf4j-api:1.7.4'
2. Super CSV common classes
Let’s go through main classes we need to know about while working with Super CSV for reading or writing CSV files.
2.1. ICsvBeanReader and CsvBeanReader
ICsvBeanReader (interface) and CsvBeanReader (implementing class) are used to read CSV files. It reads a CSV file by instantiating a bean for every row and mapping each column to a field on the bean.
The bean to populate can be either a class or interface. If a class is used, it must be a valid Java bean, i.e. it must have a default no-argument constructor and getter/setter methods. An interface may also be used if it defines getters/setters – a proxy object will be created that implements the interface.
2.2. ICsvBeanWriter and CsvBeanWriter
ICsvBeanWriter (interface) and CsvBeanWriter (implementing class) are used to write CSV files. It writes a CSV file by mapping each field on the bean to a column in the CSV file (using the supplied name mapping).
2.3. CellProcessor
CellProcessor instances are used to read a value from CSV file and process it before setting it to java bean class/interface. e.g. We want to convert a value to Date
object or even you may want to run some regex validation over values.
2.4. CsvPreference
Before reading or writing CSV files, you must supply the reader/writer with some preferences. Essentially it means that you are setting delimiter related configuration in CSV file. e.g. CsvPreference.STANDARD_PREFERENCE means :
Quote character = " Delimiter character = , End of line symbols = \r\n
We can also create your own preferences. For example if your file was pipe-delimited, you could use the following:
private static final CsvPreference PIPE_DELIMITED = new CsvPreference.Builder('"', '|', "\n").build();
3. How to read a CSV file
Now let’s see an example of reading a CSV file using above described classes. I will read below given data.csv
:
CustomerId,CustomerName,Country,PinCode,Email 10001,Lokesh,India,110001,abc@gmail.com 10002,John,USA,220002,def@gmail.com 10003,Blue,France,330003,ghi@gmail.com 10004,Reddy,Jermany,440004,abc@gmail.com 10005,Kumar,India,110001,def@gmail.com 10006,Paul,USA,220002,ghi@gmail.com 10007,Grimm,France,330003,abc@gmail.com 10008,WhoAmI,Jermany,440004,def@gmail.com 10009,Bharat,India,110001,ghi@gmail.com 10010,Rocky,USA,220002,abc@gmail.com 10011,Voella,France,330003,def@gmail.com 10012,Gruber,Jermany,440004,ghi@gmail.com 10013,Satty,India,110001,abc@gmail.com 10014,Bean,USA,220002,def@gmail.com 10015,Krish,France,330003,ghi@gmail.com And we will be populating the instances of <code>Customer.java</code> with values of above file. package com.howtodoinjava.example; public class Customer { private Integer CustomerId; private String CustomerName; private String Country; private Long PinCode; private String Email; public Customer(){ } public Customer(Integer customerId, String customerName, String country, Long pinCode, String email) { super(); this.CustomerId = customerId; this.CustomerName = customerName; this.Country = country; this.PinCode = pinCode; this.Email = email; } //Getters and setters @Override public String toString() { return "Customer [CustomerId=" + CustomerId + ", CustomerName=" + CustomerName + ", Country=" + Country + ", PinCode=" + PinCode + ", Email=" + Email + "]"; } }
Now look at CSV file, first row is column names. They should match up exactly with the bean’s field names, and the bean has the appropriate setters defined for each field.
If the header doesn’t match (or there is no header), then we can simply define your own name mapping array. [I have commented out the line, but you may take the hint.]
package com.howtodoinjava.example; 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 bean final 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()), // CustomerId new NotNull(), // CustomerName new NotNull(), // Country new Optional(new ParseLong()), // PinCode new StrRegEx(emailRegex) // Email }; return processors; } }
Program Output.
Customer [CustomerId=10001, CustomerName=Lokesh, Country=India, PinCode=110001, Email=abc@gmail.com] Customer [CustomerId=10002, CustomerName=John, Country=USA, PinCode=220002, Email=def@gmail.com] Customer [CustomerId=10003, CustomerName=Blue, Country=France, PinCode=330003, Email=ghi@gmail.com] //... So on
4. How to partially read CSV file
Partial reading allows us to ignore columns when reading CSV files by simply setting the appropriate header columns to null
. For example, in below code I have decided NOT to read the PinCode column.
final String[] headers = new String[]{"CustomerId", "CustomerName", "Country", null, "Email"};
4.1. Complete Example
package com.howtodoinjava.example; 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 PartialReadCSVFileExample { static final String CSV_FILENAME = "data.csv"; public static void main(String[] args) throws IOException { final String emailRegex = "[a-z0-9\\._]+@[a-z0-9\\.]+"; StrRegEx.registerMessage(emailRegex, "must be a valid email address"); try(ICsvBeanReader beanReader = new CsvBeanReader(new FileReader(CSV_FILENAME), CsvPreference.STANDARD_PREFERENCE)) { //First column is header beanReader.getHeader(true); //Set null for columns you do not want to read //final String[] headers = beanReader.getHeader(true); final String[] headers = new String[]{"CustomerId","CustomerName","Country",null,"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()), // CustomerId new NotNull(), // CustomerName new NotNull(), // Country new Optional(new ParseLong()), // PinCode new StrRegEx(emailRegex) // Email }; return processors; } }
Program Output.
Customer [CustomerId=10001, CustomerName=Lokesh, Country=India, PinCode=null, Email=abc@gmail.com] Customer [CustomerId=10002, CustomerName=John, Country=USA, PinCode=null, Email=def@gmail.com] Customer [CustomerId=10003, CustomerName=Blue, Country=France, PinCode=null, Email=ghi@gmail.com] //... So on
5. how to read CSV file in key-value pair
To read in key value pairs, we need to use CsvMapReader. It allows you to retrieve each column by name from the resulting Map, though you’ll have to cast each column to it’s appropriate type.
package com.howtodoinjava.example; 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 names final 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()), // CustomerId new NotNull(), // CustomerName new NotNull(), // Country new Optional(new ParseLong()), // PinCode new StrRegEx(emailRegex) // Email }; return processors; } }
Program Output.
{Country=India, CustomerId=10001, CustomerName=Lokesh, Email=abc@gmail.com, PinCode=110001} {Country=USA, CustomerId=10002, CustomerName=John, Email=def@gmail.com, PinCode=220002} {Country=France, CustomerId=10003, CustomerName=Blue, Email=ghi@gmail.com, PinCode=330003} //... So on
6. How to read CSV file with arbitrary number of columns
Some CSV files don’t conform to RFC4180 and have a different number of columns on each row. If you have got such a CSV file, then your will need to use CsvListReader, as it’s the only reader that supports it.
Read such files is tricky, as you do not know the number of columns in any row. So you read all columns in a row in a List
and then based on size of list, you determine how you may want to handle the read values.
Let’s modify the data.csv
and remove some data from it randomly.
CustomerId,CustomerName,Country,PinCode,Email 10001,Lokesh,India,110001,abc@gmail.com 10002,John,USA 10003,Blue,France,330003
Let’s read this CSV file.
package com.howtodoinjava.example; 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()), // CustomerId new NotNull(), // CustomerName new NotNull(), // Country new Optional(new ParseLong()), // PinCode new StrRegEx(emailRegex) // Email }; return processors; } private static CellProcessor[] getFourColumnProcessors() { final CellProcessor[] processors = new CellProcessor[] { new NotNull(new ParseInt()), // CustomerId new NotNull(), // CustomerName new NotNull(), // Country new Optional(new ParseLong()) // PinCode }; return processors; } private static CellProcessor[] getThreeColumnProcessors() { final CellProcessor[] processors = new CellProcessor[] { new NotNull(new ParseInt()), // CustomerId new NotNull(), // CustomerName new NotNull() //Country }; return processors; } }
Program Output.
rowNo=2, customerList=[10001, Lokesh, India, 110001, abc@gmail.com] rowNo=3, customerList=[10002, John, USA] rowNo=4, customerList=[10003, Blue, France, 330003]
7. How to Write a new CSV file
Writing a CSV file is as much simple as it was for reading the CSV file. Create CsvBeanWriter instance, define headers and processors and write the beans. It will generate the CSV file with data values populated from beans.
Super csv writer example.
package com.howtodoinjava.example; 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.ExceptionInInitializerError private 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()), // CustomerId new NotNull(), // CustomerName new NotNull(), // Country new Optional(new ParseLong()), // PinCode new 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 header beanWriter.writeHeader(header); // write the beans data for (Customer c : customers) { beanWriter.write(c, header, processors); } } catch (IOException e) { e.printStackTrace(); } finally { try { beanWriter.close(); } catch (IOException e) { e.printStackTrace(); } } } }
Output of above program will be written in file temp.csv
as below:
CustomerId,CustomerName,Country,PinCode,Email 1,Lokesh,India,12345,howtodoinjava@gmail.com 2,Mukesh,India,34234,mukesh@gmail.com 3,Paul,USA,52345345,paul@gmail.com
That’s all for simple usecases and examples of using Super CSV for reading and writing CSV files in various ways.
Drop me your questions in comments section.
Happy Learning !!
i want a number which is includes grouping separator and deciaml separator like 987,234.12
i want convert the number as it in csv file and need to open in excel all so in same format. I was used opencsv which removes comma in the number and producing 987234.12. how to solve this issue.
i want to generate csv file through rest api and need to zip all the csv files without saving to disk.Zip file should generate with all the csv files.Any suggestions.