How to write a CSV file
Short answer
Build the lines with String.join() and write them with Files.write():
record Product(String name, double price) {}
void main() throws IOException {
var products = List.of(new Product("Tea", 3.5), new Product("Cake", 12.0));
var lines = new ArrayList<String>();
lines.add("name,price");
for (Product p : products) {
lines.add(String.join(",", p.name(), String.valueOf(p.price())));
}
Files.write(Path.of("products.csv"), lines);
IO.print(Files.readString(Path.of("products.csv")));
}Output:
name,price
Tea,3.5
Cake,12.0Escaping
A value with a comma, a quote or a line break is wrapped in quotes, and quotes inside are doubled:
String csv(String value) {
if (value.contains(",") || value.contains("\"") || value.contains("\n")) {
return "\"" + value.replace("\"", "\"\"") + "\"";
}
return value;
}
void main() {
IO.println(csv("Tea"));
IO.println(csv("Smith, John"));
IO.println(csv("The \"Best\" cake"));
}Output:
Tea
"Smith, John"
"The ""Best"" cake"With a stream
Lines are easy to build with a stream:
void main() throws IOException {
var rows = List.of(List.of("Anna", "30"), List.of("Oleg", "25"));
var lines = rows.stream().map(row -> String.join(",", row)).toList();
Files.write(Path.of("people.csv"), lines);
IO.println(Files.readAllLines(Path.of("people.csv")));
}Output:
[Anna,30, Oleg,25]Common mistake
Writing decimals with String.format("%.2f") without a locale. On a computer with a German or Russian locale you get 3,50, and the comma splits the value into two cells. Use String.valueOf() or String.format(Locale.ROOT, "%.2f", value).
Functions used in this recipe
- Files.writeString() — Writes a string to a file, creating or overwriting it.
- Collectors.joining() — A collector that joins the strings of a stream into one.
- String.replace() — Replaces every occurrence of a substring or a character with another string.