Cómo leer y escribir archivos CSV con Java
Menú de navegaciónMenú
Categorías

La mejor forma de Aprender Programación online y en español www.campusmvp.es

Cómo leer y escribir archivos CSV con Java

Imagen ornamental

Una situación muy habitual en cualquier aplicación consiste en la necesidad de leer y escribir archivos con valores separados por comas (CSV, de su nombre en inglés: Comma Separated Values).

Esto se puede hacer nativamente en Java usando las API de lectura y escritura de archivos y procesando cada línea con código específico para separar los valores o para crear las líneas correspondientes. Pero hacerlo así, "a pelo" es un trabajo muy ingrato, propenso a errores y que tiene poco sentido si podemos hacerlo de una manera mejor y más directa. Y esto precisamente es lo que nos proporciona la conocida biblioteca Open Source llamada opencsv.

Además su licencia es de tipo Apache 2.0, lo que nos permite usarla para cualquier propósito, incluso para crear aplicaciones comerciales.

Aunque opencsv tiene infinidad de posibilidades, vamos a ver los métodos más sencillos para poder usarla en nuestras aplicaciones, sean estas de escritorio, Web, etc...

Cómo es un archivo CSV

Como su propio nombre indica, un archivo CSV consiste en una serie de valores separados por comas, que es el caso más habitual, aunque en realidad las comas muchas veces pueden ser otros caracteres, como puntos y coma, tabuladores, etc...

Por regla general estos archivos comienzan con una línea que lleva los nombres de cada uno de los campos de datos que se están almacenando.

Por ejemplo, el siguiente es un fragmento de un archivo CSV que representaría información sobre los códigos estándar para representar a los diferentes países del mundo. Incluye el nombre del país, su código de 2 caracteres, de 3 caracteres, su código numérico y si es considerado un estado soberano o no (sacada de aquí):

English-Short-Name,Alpha-2-code,Alpha-3-code,Numeric-code,Independent
Afghanistan,AF,AFG,4,Yes
Åland Islands,AX,ALA,248,No
Albania,AL,ALB,8,Yes
....
Spain,ES,ESP,724,Yes

La primera fila contiene el nombre de los diferentes campos, y cada una de las siguientes lleva los valores de esos campos de cada registro.

Puedes descargar el archivo entero desde aquí (ZIP, 3.5KB).

Procesar este tipo de archivos es muy sencillo pues es leer las líneas una a una y separarlas por las comas para obtener los campos correspondientes, así que se puede hacer con las capacidades básicas de cualquier lenguaje de programación o plataforma. Ahora bien, se pueden dar muchos casos especiales que hay que tener en cuenta, como campos vacíos por el medio, campos vacíos al final, valores que lleven comas como parte de su contenido... Y entonces la cosa empieza a complicarse.

Cómo leer archivos CSV con Java y opencsv

Lo primero es hacerse con el JAR de opencsv, que puedes descargar desde su página de SourceForge. Una vez descargado y añadido a tu proyecto el código necesario es muy directo:

String archCSV = "D:\\ISO-Codes.csv";
CSVReader csvReader = new CSVReader(new FileReader(archCSV));
String[] fila = null;
while((fila = csvReader.readNext()) != null) {
    System.out.println(fila[0]
              + " | " + fila[1]
              + " |  " + fila[2]);
}

csvReader.close();

Este código tan sencillo lo que hace es crear una instancia de la clase CSVReader expuesta por opencsv a la que le pasa en su constructor el FileReader de Java necesario para leer el archivo que nos interesa. Luego en un bucle indefinido de tipo while se recorren todas las filas una a una para leerlas y mostrar los valores de cada campo por la consola.

Fíjate en que, una vez leída una fila con readNext(), se obtiene un array que en cada una de sus posiciones tiene el valor correspondiente, y ya se tiene en cuenta cosas como las mencionadas (que falte un campo, etc...).

Usar un separador distinto a la coma

Si el separador utilizado fuera otro diferente (por ejemplo un ; en vez de una coma, cosa que hace Excel en Español cuando exportas una hoja de cálculo a CSV), simplemente deberías indicar dicho separador como segundo parámetro del constructor, así:

CSVReader csvReader = new CSVReader(new FileReader(archCSV), ';');

Fíjate que en este caso se usan comillas simples y no dobles ya que se trata de un literal de tipo char, no de una cadena. Si necesitamos usar caracteres especiales podemos "escapearlos" de la manera habitual. Por ejemplo, para usar un tabulador podríamos escribir:

CSVReader csvReader = new CSVReader(new FileReader(archCSV), '\t');

Datos con el separador dentro y "escapeados"

En los archivos CSV si necesitas incluir una coma dentro de un dato lo habitual es "escapear" ese valor utilizando un carácter delimitador que se pone al principio y al final del campo.

Por ejemplo, imagínate que tu dato contiene un valor decimal en español, que utiliza la coma, algo así:

Producto,Precio Kg,Disponible
Queso, "6,57",Sí
Pan, "1,32",No

En este tipo de casos lo más normal sería que cambiásemos el carácter delimitador, pero quizá no podemos. Por ello, lo que se hace es usar comillas dobles para envolver el valor del campo, como hemos hecho en este caso. Así, el precio del Queso, que son 6,57€/Kg, queda perfectamente delimitado y la coma que lleva dentro no se confunde con las comas que se utilizan como separadores de los valores.

Por defecto opencsv considera que las comillas dobles son el delimitador que se usa para este tipo de casos. Por ello no tendremos que hacer nada si es el que utiliza nuestro archivo. Pero si no es este el caso y se ha utilizado otro delimitador cualquiera (por ejemplo, unos "pipes", |, algo también muy habitual), se puede indicar como tercer parámetro del constructor:

CSVReader csvReader = new CSVReader(new FileReader(archCSV), '\t', '\|');

En este caso estaríamos indicando que el separador de valores es el tabulador y el delimitador de éstos es el "pipe".

Leer todas las filas de golpe

Si quisieras leer y obtener todas las líneas de golpe en lugar de ir una a una podrías usar el método readAll():

CSVReader csvReader = new CSVReader(new FileReader(archCSV));
List<String[]> datos = csvReader.readAll();

que ya nos entregaría una lista de matrices de cadenas que podemos procesar del mismo modo pero en un bucle determinado de tipo for.

Cómo generar archivos CSV con Java y opencsv

Ahora que ya sabemos cómo escribir los archivos, vamos a realizar el proceso inverso: partiendo de unos datos que tenemos en memoria (quizá en una matriz o una lista de objetos), vamos a crear en disco un archivo .csv con esa información delimitada por comas.

Suponiendo que queremos ir escribiendo línea por línea, el proceso se parece mucho al de lectura, usando un CSVWriter en lugar de la clase que usábamos para leer:

String [] pais = {"Spain", "ES", "ESP", "724", "Yes"};

String archCSV = "D:\\ISO-Codes.csv";
CSVWriter writer = new CSVWriter(new FileWriter(archCSV));

writer.writeNext(pais);

writer.close();

En este caso, por sencillez, estamos simulando que tenemos un dato metido en un array, pero en la práctica obtendríamos esta información de una base de datos, de la entrada de un usuario, etc... Eso ya es cosa tuya. Pero el proceso sería el mismo.

Si tenemos más de un dato al mismo tiempo (por ejemplo un conjunto de registros sacados de una base de datos) y queremos escribirlos todos de golpe, podemos usar writeAll() para ello:

//Creo mi lista de países (los sacaría de algún lado, aquí los creamos a mano para el ejemplo)
List<String[]> paises = new ArrayList<String[]>;
paises.add({"Afghanistan", "AF", "AFG", "4", "Yes"});
paises.add({"Spain", "ES", "ESP", "724", "Yes"});
//Etc...

String archCSV = "D:\\ISO-Codes.csv";
CSVWriter writer = new CSVWriter(new FileWriter(archCSV));

writer.writeAll(paises);

writer.close();

Con esto se escribirían todos de golpe.

Del mismo modo que antes podíamos especificar el separador y el delimitador como segundo y tercer parámetro del constructor respectivamente, en el caso del CSVWriter pasa exactamente lo mismo, por lo que podríamos indicar otros distintos a la coma y las comillas dobles por defecto, para que se usasen en la generación del archivo si así fuese necesario.

Técnicas más avanzadas

Lo que acabamos de ver es la manera más simple y directa de leer y escribir CSV desde Java. Si queremos tener más potencia podemos usar otras características avanzadas de opencsv para lograrlo. Pero esto ya se sale del ámbito y del espacio disponible para un artículo como este.

Por ejemplo, en archivos cuya primera línea contiene los nombres de los campos de los registros (como en el ejemplo de los países que vimos al principio), es posible obtener directamente objetos Java Bean mapeados cuyas propiedades son dichos campos, de modo que no tengamos que manejar elementos de un array por orden usando su índice. Y lo mismo para escribirlos a disco desde objetos. Para ello te remitimos a la documentación de opencsv (lectura y escritura), así como para aprender otras características más específicas de esta biblioteca (anotaciones, filtrado de datos, saltar registros...).

campusMVP campusMVP es la mejor forma de aprender a programar online y en español. En nuestros cursos solamente encontrarás contenidos propios de alta calidad (teoría+vídeos+prácticas) creados y tutelados por los principales expertos del sector. Nosotros vamos mucho más allá de una simple colección de vídeos colgados en Internet porque nuestro principal objetivo es que tú aprendas. Ver todos los posts de campusMVP

No te pierdas ningún post

Únete gratis a nuestro canal en Telegram y te avisaremos en el momento en el que publiquemos uno nuevo.

Archivado en: Lenguajes y plataformas

Comentarios (3) -

Porqué este código no me funciona? He adjuntado mi libreria en el proyecto netbeans  pero se produce una excepción y me la da sensación que es porque la API no está bien.

Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/lang3/ObjectUtils
  at com.opencsv.CSVParser.<init>(CSVParser.java:209)
  at com.opencsv.CSVReader.<init>(CSVReader.java:196)
  at com.opencsv.CSVReader.<init>(CSVReader.java:178)
  at com.opencsv.CSVReader.<init>(CSVReader.java:130)
  at com.opencsv.CSVReader.<init>(CSVReader.java:70)
  at csvfile.CsvFile.main(CsvFile.java:21)
Caused by: java.lang.ClassNotFoundException: org.apache.commons.lang3.ObjectUtils
  at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
  at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
  at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335)
  at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
  ... 6 more

import java.io.*;
import com.opencsv.CSVReader;

public class CsvFile {

  public static void main(String[] args) throws FileNotFoundException, IOException {
    String csvFilename = "D:\\Libros\\Java\\MyProjects\\CsvFile\\ISO-Codes.csv";
                CSVReader csvReader = new CSVReader(new FileReader(csvFilename));
                String[] row = null;
            while((row = csvReader.readNext()) != null) {
                    System.out.println(row[0]
                        + " # " + row[1]
                        + " #  " + row[2]);
                }
            //...
        csvReader.close();
    
  }

}

Gracias de antemano por responder.

Responder

Hola Blanca:

Ese error te lo da porque te falta el archivo:

commons-lang3-3.0.jar

en tu classpath, y es necesario. Añádelo y te compilará.

Saludos.

Responder

Gracias, funciona perfecto!

Responder

Agregar comentario