Java no trae un lector de CSV, y el formato tiene más trampas de las que parece: el separador cambia según el país, los campos pueden llevar comillas dentro y los decimales dependen del idioma. Con cuarenta líneas se resuelve bien.
También te puede interesar
Escribir
try (var w = Files.newBufferedWriter(f, StandardCharsets.UTF_8)) {
w.write("nombre;ciudad;precio\n");
for (var x : filas)
w.write(String.join(";", cita(x.nombre()), cita(x.ciudad()),
String.format(Locale.US, "%.2f", x.precio())) + "\n");
}
// entrecomilla si hay separador, comillas o saltos de línea
String cita(String v) {
if (v.contains(";") || v.contains("\"") || v.contains("\n"))
return '"' + v.replace("\"", "\"\"") + '"';
return v;
}
datos.csvnombre;ciudad;precio gorra;Madrid;12.50 "bufanda ""larga""";Bilbao;9.00 "mochila; grande";A Coruña;34.00
Dos detalles que separan un CSV que funciona de uno que rompe la hoja de cálculo del cliente:
- El entrecomillado. Si el campo contiene el separador, un salto de línea o comillas, va entre comillas, y las comillas de dentro se duplican. Ahí está
bufanda ""larga"". Locale.USen elformat. Sin eso, en una máquina configurada en español el precio saldría12,50con coma… que es justo el separador de muchos CSV. Es un fallo que no aparece en tu portátil y sí en el servidor.
StandardCharsets.UTF_8. Desde Java 18 el valor por omisión ya es UTF-8, pero escribirlo documenta la intención y protege de una configuración rara. Si el destino es Excel en Windows, puede que necesites windows-1252 o un BOM.Leer
try (var r = Files.newBufferedReader(f, StandardCharsets.UTF_8)) {
String cab = r.readLine();
String linea;
while ((linea = r.readLine()) != null) {
String[] c = partir(linea, ';');
System.out.printf(" %-18s %-10s %8.2f%n", c[0], c[1], Double.parseDouble(c[2]));
}
}
salidacabecera: [nombre, ciudad, precio] gorra Madrid 12.50 bufanda "larga" Bilbao 9.00 mochila; grande A Coruña 34.00
Volvieron enteros, con las comillas deshechas y el punto y coma de «mochila; grande» intacto. Eso lo hace el analizador, que es la pieza que de verdad importa:
String[] partir(String linea, char sep) {
var out = new ArrayList<String>();
var actual = new StringBuilder();
boolean dentro = false;
for (int i = 0; i < linea.length(); i++) {
char c = linea.charAt(i);
if (dentro) {
if (c == '"' && i + 1 < linea.length() && linea.charAt(i + 1) == '"') { actual.append('"'); i++; }
else if (c == '"') dentro = false;
else actual.append(c);
} else if (c == '"') dentro = true;
else if (c == sep) { out.add(actual.toString()); actual.setLength(0); }
else actual.append(c);
}
out.add(actual.toString());
return out.toArray(new String[0]);
}
linea.split(";"). Funciona hasta el primer campo que lleve un punto y coma dentro, y entonces te desplaza todas las columnas en silencio. Si el archivo viene de fuera, siempre hay uno.Lo que esto no cubre
Este analizador vale para CSV bien formado de una línea por registro. Lo que le falta: campos con saltos de línea dentro de las comillas, que obligan a leer por caracteres y no por líneas, y la detección automática del separador. Si el archivo es ajeno y grande, lo sensato es Commons CSV o FastCSV, que además son bastante más rápidos.
Todo el código se compiló y se ejecutó con Java 25 LTS en un contenedor limpio antes de publicar esta página; las salidas están copiadas de esa ejecución.