Leer y escribir CSV en Java con OpenCSV

Este es el artículo final de una breve serie dedicada a las bibliotecas para leer y escribir archivos CSV en Java, y una continuación directa del artículo anterior:...

Introducción

This is the final article in a short series dedicated to Bibliotecas para leer y escribir CSV en Java, and a direct continuation from the previous article - Leer y escribir CSV en Java con Apache Commons CSV.

CSV abierto

OpenCSV es uno de los analizadores de CSV más simples y fáciles de entender, utiliza clases estándar Reader/Writer y ofrece una implementación CSVReader en la parte superior.

Al igual que Apache Commons CSV, OpenCSV funciona con una licencia Apache 2.0. Antes de descargar y decidir si usar los analizadores de OpenCSV, puede navegar por el código fuente y documentos de Java, e incluso consultar su conjunto de pruebas JUnit, que está incluido en su repositorio git.

OpenCSV también se incluye en MVNRepositorio, lo que simplifica la administración de dependencias.

El CSVReader permite obtener un solo registro a la vez, múltiples registros como una lista o como un iterador, lo que lo hace flexible en términos de usabilidad de los datos leídos. La biblioteca también incluye funciones prácticas como lectura, escritura desde y hacia beans y mapeo directo de un CSV a un mapa de Java usando la fila de encabezado.

OpenCSV no tiene una variedad tan amplia de formatos predefinidos como Apache Commons CSV. Se basa en dos analizadores:

  • CSVParser: el analizador original definido en OpenCSV. Esto funciona para la mayoría de las instancias de análisis simples, pero falla si hay caracteres de escape definidos como parte del propio registro.
  • RFC4180Parser - similar al analizador CSVFormat.RFC4180 en Apache Commons CSV. Funciona en archivos CSV que están formateados de acuerdo con las especificaciones de RFC 4180. Esta versión del analizador considera todos los caracteres entre las comillas de apertura y cierre como contenido, excepto el carácter de comilla doble, que debe escaparse con otra comilla doble.

Leer CSV con OpenCSV

La lectura de CSV con OpenCSV es más rápida que con Apache Commons CSV porque CSVWriter se implementa para ser multihilo, cuando se usa el método CSVToBean.parse().

El CSVReader también se implementa utilizando Java Iterable, por lo que es posible administrar las limitaciones de memoria y tiempo en función del método de implementación que elija.

OpenCSV tiene dos tipos de objetos para leer CSV: CSVReader y su subclase CSVReaderHeaderAware.

CSVReader es similar a su contraparte de Apache Commons CSV CSVParser y se puede usar tanto para escenarios de análisis simples como complicados.

Para iterar a través de cada registro en un archivo CSV, donde record será una matriz de cadenas con los valores separados por comas divididos en campos individuales:

1
2
3
4
CSVReader csvReader = new CSVReader (new InputStreamReader(csvFile.getInputStream()));
while ((record = csvReader.readNext()) != null) {
    // do something
}

Si su CSV está delimitado por un carácter que no sea una coma, puede usar el constructor de dos parámetros en su lugar y especificar el delimitador que desea que use el CSVReader.

Por ejemplo, si su CSV contiene valores separados por tabuladores, puede inicializar el CSVReader de la siguiente manera:

1
CSVReader csvReader = new CSVReader(new InputStreamReader(csvFile.getInputStream()), '\t');

OpenCSV también tiene una forma más complicada de analizar archivos CSV que implica implementar beans para mapear los campos en un CSV y luego usar anotaciones para identificar los tipos de registros con anotaciones basadas en encabezados o posiciones.

Esto ayuda porque permite que los registros de un CSV se procesen como un conjunto de datos común, en lugar de como una colección de campos individuales.

Si los nombres de encabezado del archivo que se procesa son consistentes, puede anotar las columnas usando la anotación @CSVBindByName y permitir que OpenCSV se encargue del mapeo y la copia del procesamiento de los datos analizados.

Por ejemplo, con nuestro conjunto de datos de árbol:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Trees {
    @CSVBindByName
    private int index;

    @CSVBindByName
    private int girth;

    @CSVBindByName
    private int height;

    @CSVBindByName
    private int volume;

    public int getIndex() {
        return this.index;
    }

    public void setIndex(int newIndex) {
        this.index = newIndex;
    }
    ...
}

Siempre que su archivo CSV contenga un encabezado con los nombres de las variables en nuestra declaración de clase, OpenCSV puede analizar y leer datos en el elemento correspondiente, y las conversiones de tipo se manejan automáticamente:

1
List<Trees> treeParser = new CSVToBeanBuilder(FileReader("somefile.csv")).withType(Trees.class).build().parse();

Se pueden agregar validaciones a los métodos getter y setter cuando sea necesario, y los campos obligatorios se pueden especificar configurando el indicador requerido en la anotación.

Si el nombre del encabezado es ligeramente diferente del nombre de la variable, la cadena también se puede establecer en la anotación. La capacidad de asignar el nombre del encabezado cuando el nombre de la columna es diferente es útil en nuestro ejemplo, ya que nuestro conjunto de datos real contiene la unidad de medida del campo, junto con un espacio y caracteres de puntuación que no están permitidos en los nombres de variables estándar de Java.

La bandera y el mapeo se pueden especificar con la anotación en este caso:

1
2
3
4
...
    @CSVBindByName (column = "Girth (in)", required = true)
    private int girth;
...

Si su archivo CSV no tiene un encabezado, puede mapear por posición de columna junto con la anotación @CSVBindByPosition.

Tenga en cuenta que las posiciones de OpenCSV están basadas en 0:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
public class Trees{
    @CSVBindByPosition(position = 0, required = true)
    private int index;

    @CSVBindByPosition(position = 1, required = true)
    private int girth;

    @CSVBindByPosition(position = 2)
    private int height;

    @CSVBindByPosition(position = 3)
    private int volume;
}

Si desea manejar escenarios más complicados, puede implementar una clase con Interfaz MappingStrategy y definir el esquema de traducción o mapeo que se adapte a su escenario de análisis.

Escribir CSV con OpenCSV

OpenCSV tiene más opciones que Apache Commons CSV cuando se trata de escribir datos en archivos CSV. Le permite escribir desde una matriz de cadenas o escribir desde una lista de objetos.

Escribir desde una lista de objetos requiere que los objetos se inicialicen y declaren de antemano. Entonces, para simplificar las cosas, consideremos trabajar con una matriz de cadenas.

Para generar un archivo CSV con datos de una matriz de cadenas:

1
2
3
4
CSVWriter csvWriter = new CSVWriter(new FileWriter("new.csv"), ',');
String[] records = "Index.Girth.Height.Volume".split(".");
csvWriter.writeNext(records);
csvWriter.close();

OpenCSV funciona con el concepto de que CSV no son solo valores separados por comas; te permite definir qué delimitador quieres usar en el archivo como parámetro en el constructor CSVWriter.

De manera similar, al definir una matriz de cadenas, puede resultarle útil declarar una cadena y luego separarla en valores basados ​​en un delimitador. Esto es especialmente útil cuando necesita copiar un subconjunto seleccionado de filas de datos de un archivo CSV o de base de datos a otro.

Al inicializar el CSVWriter, el FileWriter o Writer es obligatorio. La inicialización del escritor usando solo un parámetro da como resultado un archivo predeterminado separado por comas.

Hay algunos parámetros adicionales para casos de uso específicos:

  • Separador de caracteres - el delimitador. Si no se declara, el delimitador predeterminado será una coma.
  • Char quotechar - el carácter de comillas. Esto se usará en caso de que su conjunto de datos contenga un valor con una coma como parte del conjunto de datos y necesite generar un archivo separado por comas. En general, se utilizan comillas dobles, comillas simples o barras oblicuas como caracteres de comillas.
  • Char escapechar - Esto se usa generalmente para escapar del quotechar.
  • String lineend: la cadena o el carácter que determina el final de una línea de datos.

Podrías construir el CSVWriter incluyendo todos los parámetros opcionales:

1
CSVWriter csvWriter = new CSVWriter(new FileWriter("new.csv"), ",", "'","/", "\n");

CSVWriter también tiene algunos campos que puede pasar como parámetros al constructor. Puede definir estos valores como constantes y reutilizar los caracteres y las cadenas en su base de código para preservar la coherencia.

Por ejemplo, después de declarar:

1
2
3
4
CSVWriter.DEFAULT_SEPARATOR = ",";
CSVWriter.DEFAULT_QUOTE_CHARACTER = "'";
CSVWriter.DEFAULT_ESCAPE_CHARACTER = "/";
CSVWriter.DEFAULT_LINE_END = "\n";

Podrías usar:

1
CSVWriter csvWriter = new CSVWriter(new FileWriter("new.csv"), CSVWriter.DEFAULT_SEPARATOR, CSVWriter.DEFAULT_QUOTE_CHARACTER, CSVWriter.DEFAULT_ESCAPE_CHARACTER, CSVWriter.DEFAULT_LINE_END);

O use OpenCSV usando los valores predeterminados si los valores no están definidos explícitamente en el constructor y simplemente llame:

1
CSVWriter csvWriter = new CSVWriter(new FileWriter("new.csv"));

Entonces, si sus datos incluyen una línea con un nombre de usuario y una dirección, por ejemplo: JohnDoe, 19/2, ABC Street, Someplace, el formato de cadena real en el que necesitaría que estuviera es "JohnDoe\ “, "19//2/, Calle ABC/, En algún lugar".

Conclusión

OpenCSV es uno de los analizadores de CSV más simples y fáciles de entender, utiliza clases estándar Reader/Writer y ofrece una implementación CSVReader en la parte superior.

Licensed under CC BY-NC-SA 4.0