Introduction
Apache Commons CSV is one of the components in the Apache Commons project. We can use Apache Commons CSV to read and write Comma Separated Value (CSV) files. In one of the earlier posts, I have shown how to read CSV files using Apache Commons CSV. In this post, we will look on how to write CSV files using Apache Commons CSV.
Using Apache Commons CSV
Refer to the Importing Apache Commons CSV section from the earlier post on reading CSV files.
Writing CSV files
I’ll continue to use the same data set or example from the earlier post for reading CSV files i.e., Student details.
As in the other post, the first step in writing CSV data is to first create a CSVFormat. To read data, we called the parse method on the CSVFormat. To write data, we can call one of the many available print methods. The print methods return a CSVPrinter object that can be used to write CSV data.
Writing CSV to an Appendable
The first variation of the print method we will see takes an Appendable and writes data into that.
String outputFilePath = ".../csvFile.csv";
BufferedWriter bufferedWriter = Files.newBufferedWriter(Paths.get(outputFilePath));
try (CSVPrinter csvPrinter = CSVFormat.DEFAULT
.print(bufferedWriter)) {
csvPrinter.printRecord("100", "John Doe", "4.5");
csvPrinter.printRecord("101", "Mark Cooper", "3.8");
}
First, we create a BufferedWriter using Files.newBufferedWriter method by passing the path to the CSV file. Next, we create the Path instance from the target path/location using the static Paths.get method.
After creating a CSVFormat with default properties (comma as delimiter), we call the print method passing the created buffered writer. This returns a CSVPrinter. A BufferedWriter extends Writer which is an Appendable. Then, we write the individual rows or records using the printRecord method. It writes the values using the configured delimiter into the appendable and adds the record separator after writing the values.
Important: It is necessary to flush (and close) the underlying BufferedWriter after writing all data and without which data may not get written or may get written partially. Since, we are using the try-with-resources block, it closes the CSVPrinter which inturn closes the underlying appendable (the BufferedWriter). Closing an appendable will also flush the buffered data to the file.
The generated file will have the below content
100,John Doe,4.5
101,Mark Cooper,3.8
Writing CSV data using a File or a Path
There is a print method that takes a File object or just a Path. Passing a File object to the print method looks like
String outputFilePath = ".../csvFile.csv";
try (CSVPrinter csvPrinter = CSVFormat.DEFAULT
.print(new File(outputFilePath), Charset.forName("UTF-8"))) {
csvPrinter.printRecord("100", "John Doe", "4.5");
csvPrinter.printRecord("101", "Mark Cooper", "3.8");
}
We can also just create a Path object and pass it to the print method as,
try (CSVPrinter csvPrinter = CSVFormat.DEFAULT
.print(Paths.get(outputFilePath), Charset.forName("UTF-8"))) {
csvPrinter.printRecord("100", "John Doe", "4.5");
csvPrinter.printRecord("101", "Mark Cooper", "3.8");
}
The end result (the CSV file contents) will be the same as seen in the first section when we passed an Appendable.
Using the printRecord method
There is a printRecord method which takes both the values and the appendable as parameters. It writes the passed values using the configured delimiter into the appendable (CSV file here) and adds the record separator. Since, we are using the default CSVFormat the delimiter and record separator is a comma and newline, respectively.
try (BufferedWriter writer = Files.newBufferedWriter(Paths.get(outputFilePath))) {
CSVFormat.DEFAULT.printRecord(writer, "100", "John Doe", "4.5");
CSVFormat.DEFAULT.printRecord(writer, "101", "Mark Cooper", "3.81");
}
Printing CSV data to System.out
CSVFormat class has a printer method which returns a CSVPrinter configured with System.out as the underlying Appendable. Hence, this method can be used to print CSV data to the terminal.
CSVPrinter csvPrinter = CSVFormat.DEFAULT.printer();
csvPrinter.printRecord("100", "John Doe", "4.5");
csvPrinter.printRecord("101", "Mark Cooper", "3.8");
Prints the following data to the terminal
100,John Doe,4.5
101,Mark Cooper,3.8
Writing CSV data with headers
You would have noticed that the CSV data we have written so far did not have any headers. It is straightforward to configure the headers using the withHeader method of the CSVFormat.
String outputFilePath = ".../csvFileWithHeaders.csv";
BufferedWriter bufferedWriter = Files.newBufferedWriter(Paths.get(outputFilePath));
try (CSVPrinter csvPrinter = CSVFormat.DEFAULT.withHeader("StudentId", "StudentName", "StudentGPA")
.print(bufferedWriter)) {
csvPrinter.printRecord("100", "John Doe", "4.5");
csvPrinter.printRecord("101", "Mark Cooper", "3.8");
}
After running this, the file csvFileWithHeaders.csv has the below data
StudentId,StudentName,StudentGPA
100,John Doe,4.5
101,Mark Cooper,3.8
CSV file with a different (custom) delimiter
The delimiter can be configured when creating the CSVFormat object. Let us configure the delimiter as a hyphen (“-“).
String outputFilePath = "../csvFileWithDiffDelimiter.csv";
BufferedWriter bufferedWriter = Files.newBufferedWriter(Paths.get(outputFilePath));
try(CSVPrinter csvPrinter = CSVFormat.newFormat('-')
.withRecordSeparator('\n')
.print(bufferedWriter)) {
csvPrinter.printRecord("100", "John Doe", "4.5");
csvPrinter.printRecord("101", "Mark Cooper", "3.8");
}
The result file contents (csvFileWithDiffDelimiter.csv) look like
100-John Doe-4.5
101-Mark Cooper-3.8
Conclusion
We saw how to write CSV files using Apache Commons CSV. In particular, we looked at how CSVFormat can be configured and the different varieties of the print method on a CSVPrinter that can be used to write CSV data. Check out the post on how to read CSV data if you haven’t read it already.