In an earlier article, I discussed how to read and write CSV files using Apache Commons CSV. This article is a direct continuation of the previous article and part of the series about libraries that can be used to read and write CSV files in Java.
Today, we shall learn about another open-source library, OpenCSV, to read and write CSV files in Java. OpenCSV is another popular library for reading, writing, parsing, serializing, and deserializing CSV files in Java.
Dependencies
Before we move on to parsing or writing CSV files, you only need OpenCSV dependency for your project. If you are using Gradle, add the following dependency to the build.gradle
file:
implementation 'com.opencsv:opencsv:4.6'
For the Maven project, you should add the below dependency to the pom.xml
file:
<dependency>
<groupId>com.opencsv</groupId>
<artifactId>opencsv</artifactId>
<version>4.6</version>
</dependency>
Sample CSV Files
Let us use the same CSV files we used for the Commons CSV examples for reading and parsing using OpenCSV.
Here is the first CSV without a header:
users.csv
1,Atta Shah,atta@example.com,PK
2,Alex Jones,alex@example.com,DE
3,Jovan Lee,jovan@example.com,FR
4,Greg Hover,greg@example.com,US
The second CSV file with a header:
users-with-header.csv
id,name,email,country
1,Atta Shah,atta@example.com,PK
2,Alex Jones,alex@example.com,DE
3,Jovan Lee,jovan@example.com,FR
4,Greg Hover,greg@example.com,US
Reading CSV Files
There are multiple ways to read a CSV file with OpenCSV. You can choose to read the CSV file either line-by-line or at once.
Similarly, you can decide whether to read the record as a string array or bind the record into an object. Let us look at all these approaches below.
Reading a CSV file with each record as a string array
The simplest way to read a CSV file using OpenCSV is by reading each record into a string array. Here is an example that uses the CSVReader
class to read one line at a time from the file:
try {
// create a reader
Reader reader = Files.newBufferedReader(Paths.get("users.csv"));
// create csv reader
CSVReader csvReader = new CSVReader(reader);
// read one record at a time
String[] record;
while ((record = csvReader.readNext()) != null) {
System.out.println("ID: " + record[0]);
System.out.println("Name: " + record[1]);
System.out.println("Email: " + record[2]);
System.out.println("Country: " + record[3]);
}
// close readers
csvReader.close();
reader.close();
} catch (IOException ex) {
ex.printStackTrace();
}
Reading all records at once
In the example above, the readNext()
method reads the next line from the buffer and converts it to a string array. The CSVReader
class also provides a method called readAll()
that reads the entire file into a List
with each element being a String[]
of tokens:
try {
// create a reader
Reader reader = Files.newBufferedReader(Paths.get("users.csv"));
// create csv reader
CSVReader csvReader = new CSVReader(reader);
// read all records at once
List<String[]> records = csvReader.readAll();
// iterate through the list of records
for (String[] record : records) {
System.out.println("ID: " + record[0]);
System.out.println("Name: " + record[1]);
System.out.println("Email: " + record[2]);
System.out.println("Country: " + record[3]);
}
// close readers
csvReader.close();
reader.close();
} catch (IOException ex) {
ex.printStackTrace();
}
The above approach is not recommended for larger CSV files as it loads the entire file contents into memory.
Skipping the header
There is no way to skip the header record when using the CSVReader
class. If you read a file that contains a header, then the header will also be printed on the console.
Instead, you should use CSVReaderBuilder
, which provides greater flexibility and more configuration options, including the ability to skip the header record.
Let us use the CSVReaderBuilder
class to create a CSVReader
object with a specified number of records skipped:
CSVReader csvReader = new CSVReaderBuilder(reader).withSkipLines(1).build();
CSVParserBuilder
allows you to choose a custom column separator, ignore or handle quotations marks, decide what to do with null
fields, and how to interpret escaped characters:
CSVParser parser = new CSVParserBuilder()
.withSeparator('\t')
.withFieldAsNull(CSVReaderNullFieldIndicator.EMPTY_QUOTES)
.withIgnoreLeadingWhiteSpace(true)
.withIgnoreQuotations(false)
.withStrictQuotes(true)
.build();
CSVReader csvReader = new CSVReaderBuilder(reader)
.withSkipLines(1)
.withCSVParser(parser)
.build();
Check out the official documentation for more information on these configuration options.
Reading a CSV file with each record as a Java object using annotations
The real benefit of using OpenCSV is that you can directly map the record fields into a Java object. There are two ways of doing this. You can use annotations or mapping strategies to bind the record fields to bean attributes.
OpenCSV has two types of annotations to specify the column names mapping with object fields either by name or by position: @CsvBindByName
and @CsvBindByPosition
.
Using @CsvBindByName
annotation
You can only use the @CsvBindByName
annotation if the CSV file has a header. It accepts up to five parameters, including column
, required
, and locale
. All parameters are options except column
, which is also only required if the header column name in the CSV file is different from the bean field.
Let us first create a Java class to make use of the CsvBindByName
annotation:
User.java
public class User {
@CsvBindByName
public int id;
@CsvBindByName
public String name;
@CsvBindByName
public String email;
@CsvBindByName(column = "country")
public String countryCode;
// getters and setters omitted for brevity
}
Here is an example that reads and parses the CSV file records directly into Java objects using OpenCSV:
try {
// create a reader
Reader reader = Files.newBufferedReader(Paths.get("users-with-header.csv"));
// create csv bean reader
CsvToBean csvToBean = new CsvToBeanBuilder(reader)
.withType(User.class)
.withIgnoreLeadingWhiteSpace(true)
.build();
// iterate through users
for (User user : (Iterable<User>) csvToBean) {
System.out.println("ID: " + user.getId());
System.out.println("Name: " + user.getName());
System.out.println("Email: " + user.getEmail());
System.out.println("Country: " + user.getCountryCode());
}
// close the reader
reader.close();
} catch (IOException ex) {
ex.printStackTrace();
}
Note that we used the users-with-headers.csv
file for the above example because it contains a header.
The CsvToBean
class also provides a parse()
method that reads entire CSV file contents into memory and then parses it into a list of objects (not recommended for large CSV files):
List<User> users = csvToBean.parse();
// iterate through list
for (User user : users) {
System.out.println("ID: " + user.getId());
System.out.println("Name: " + user.getName());
System.out.println("Email: " + user.getEmail());
System.out.println("Country: " + user.getCountryCode());
}
Using @CsvBindByPosition
annotation
If the CSV file does not have a header, you use the @CsvBindByPosition
annotation to map the column position (zero-based) to bean fields like the below:
public class User {
@CsvBindByPosition(position = 0)
public int id;
@CsvBindByPosition(position = 1)
public String name;
@CsvBindByPosition(position = 2)
public String email;
@CsvBindByPosition(position = 3)
public String countryCode;
// getters and setters omitted for brevity
}
Reading a CSV file with each record as a Java object using mapping strategies
Mapping strategies are another way of mapping the CSV columns directly to Java object fields. Using this strategy, you can safely remove all OpenCSV annotations from your Java classes.
Let us first remove all annotations from the User
class:
public class User {
public int id;
public String name;
public String email;
public String countryCode;
public User(int id, String name, String email, String countryCode) {
this.id = id;
this.name = name;
this.email = email;
this.countryCode = countryCode;
}
// getters and setters omitted for brevity
}
Now let us use ColumnPositionMappingStrategy
to specify the mapping between CSV columns and Java object attributes and then parse the CSV records into Java objects:
try {
// create a reader
Reader reader = Files.newBufferedReader(Paths.get("users-with-header.csv"));
// columns name
String[] columns = {"id", "name", "email", "countryCode"};
// create a mapping strategy
ColumnPositionMappingStrategy strategy = new ColumnPositionMappingStrategy();
strategy.setType(User.class);
strategy.setColumnMapping(columns);
// create csv bean reader
CsvToBean csvToBean = new CsvToBeanBuilder(reader)
.withMappingStrategy(strategy)
.withSkipLines(1)
.withIgnoreLeadingWhiteSpace(true)
.build();
// iterate through users
for (User user : (Iterable<User>) csvToBean) {
System.out.println("ID: " + user.getId());
System.out.println("Name: " + user.getName());
System.out.println("Email: " + user.getEmail());
System.out.println("Country: " + user.getCountryCode());
}
// close the reader
reader.close();
} catch (IOException ex) {
ex.printStackTrace();
}
The ColumnPositionMappingStrategy
class uses the position of the column in the CSV file to map it to the bean attribute.
Writing CSV Files
OpenCSV allows you to generate a CSV file from an array of strings or from a list of objects. It has more configuration options than Commons CSV for writing data to CSV files. Most importantly, you can easily convert any list of objects to a CSV file by writing just a few lines of code.
Generating a CSV file from an array of strings
Here is an example that writes an array of strings to a CSV file by using OpenCSV:
try {
// create a write
Writer writer = Files.newBufferedWriter(Paths.get("users-simple.csv"));
// header record
String[] headerRecord = {"id", "name", "email", "country"};
// create a csv writer
ICSVWriter csvWriter = new CSVWriterBuilder(writer)
.withSeparator(CSVWriter.DEFAULT_SEPARATOR)
.withQuoteChar(CSVWriter.NO_QUOTE_CHARACTER)
.withEscapeChar(CSVWriter.DEFAULT_ESCAPE_CHARACTER)
.withLineEnd(CSVWriter.DEFAULT_LINE_END)
.build();
// write header record
csvWriter.writeNext(headerRecord);
// write data records
csvWriter.writeNext(new String[] {"1", "Emma Watson", "emma.watson@example.com", "UK"});
csvWriter.writeNext(new String[] {"2", "Nick Jones", "nick.jones@example.com", "DE"});
csvWriter.writeNext(new String[] {"3", "Shanzay Alai", "shanzay.alai@example.com", "US"});
// close writers
csvWriter.close();
writer.close();
} catch (IOException ex) {
ex.printStackTrace();
}
Generating a CSV file from a list of objects
Here is an example that shows how to convert a list of objects into a CSV file. It is using the User
class we defined in the previous example:
try {
// create a write
Writer writer = Files.newBufferedWriter(Paths.get("users-objects.csv"));
// create a csv writer
StatefulBeanToCsv<User> csvWriter = new StatefulBeanToCsvBuilder<User>(writer)
.withSeparator(CSVWriter.DEFAULT_SEPARATOR)
.withQuotechar(CSVWriter.NO_QUOTE_CHARACTER)
.withEscapechar(CSVWriter.DEFAULT_ESCAPE_CHARACTER)
.withLineEnd(CSVWriter.DEFAULT_LINE_END)
.withOrderedResults(false)
.build();
// create a list of objects (`User`)
List<User> users = new ArrayList<>();
users.add(new User(1, "Emma Watson", "emma.watson@example.com", "UK"));
users.add(new User(2, "Nick Jones", "nick.jones@example.com", "DE"));
users.add(new User(3, "Shanzay Alai", "shanzay.alai@example.com", "US"));
// write a list of objects
csvWriter.write(users);
// close the writer
writer.close();
} catch (Exception ex) {
ex.printStackTrace();
}
Conclusion
That is all for reading and writing CSV files in Java using the OpenCSV library. We discussed almost all ways to write and read data from a CSV file.
OpenCSV is a simple yet very powerful CSV parser that makes it a popular choice for manipulating CSV files in Java.
I appreciate your patience in reading this long article.
Further Reading
I hope you enjoy reading this article. You may be interested in reading other CSV-related articles:
- Reading and writing CSV files using Apache Commons CSV
- Reading and writing CSV files using core Java
- Export & Download Data as CSV File in Spring Boot
✌️ Like this article? Follow me on Twitter and LinkedIn. You can also subscribe to RSS Feed.