Leer y escribir archivos CSV en Node.js con node-csv

En este tutorial, usaremos la suite node-csv, o más bien, los módulos csv-parse y csv-stringify para leer y escribir archivos CSV en Node.js con ejemplos.

Introducción

Una tarea común de desarrollo es leer datos de archivos. Un formato de archivo común es el formato .csv.

Si bien puede leer archivos CSV usando el módulo fs que viene con Node y obtener el contenido del archivo, en la mayoría de los casos, el análisis y la conversión posterior son mucho más fáciles con la ayuda de módulos creados exactamente para ese propósito.

Múltiples módulos brindan capacidades tales como los paquetes neat-csv o csv-parser. Sin embargo, en este artículo, usaremos nodo-csv, un conjunto de paquetes CSV para generar, analizar, transformar y clasificar datos CSV.

Instalando node-csv

El módulo consta de los paquetes csv-generate, csv-parse, csv-transform y csv-stringify.

Puede instalar todo el paquete o cada paquete uno por uno si no los necesita todos. Inicialicemos un proyecto de nodo con la configuración predeterminada:

1
$ npm init -y

Luego, instalemos la suite node-csv completa:

1
$ npm install csv

{.icon aria-hidden=“true”}

Nota: Aunque la suite se llama node-csv, el paquete NPM relevante en realidad se llama csv.

Trabajaremos con un archivo CSV con estos contenidos:

1
2
3
4
Account Name,Account Code,Type,Description
Cash,101,Assets,Checking account balance
Wages Payable,220,Liabilities,Amount owed to employes for hours not yet paid
Rent expense,560,Expenses,Cost of occupied rented facilities during accounting period

Leer archivos CSV con csv-parse

Para leer archivos CSV, usaremos el paquete csv-analizar de node-csv.

El paquete csv-parse proporciona múltiples enfoques para analizar archivos CSV, utilizando devoluciones de llamada, una transmisión + devolución de llamada, así como la API Sync y Async. Cubriremos la transmisión + API de devolución de llamada y la API de sincronización.

Transmisión + API de devolución de llamada

Vamos a crear un archivo, llamado index.js y construir un parser:

1
2
3
4
5
6
7
var fs = require('fs'); 
var parse = require('csv-parse');
var parser = parse({columns: true}, function (err, records) {
    console.log(records);
});

fs.createReadStream(__dirname+'/chart-of-accounts.csv').pipe(parser);

Primero, importamos el módulo del sistema de archivos nativo (fs) y el módulo csv-parse. Luego, creamos un parser que acepta un objeto literal, que contiene las opciones que nos gustaría establecer. El segundo argumento es la función de devolución de llamada que se usa para acceder a los registros, o simplemente imprimirlos, en nuestro caso.

Las opciones que podemos configurar no son obligatorias. En la mayoría de los casos, usará cualquiera de las opciones delimiter, cast o columns:

  • La opción delimitador tiene como valor predeterminado una coma ,. Si los datos del archivo que está tratando de analizar utilizan algún otro delimitador como un punto y coma ;, o una barra vertical |, puede especificarlo con esta opción.

  • La opción cast por defecto es false y se usa para indicar si desea convertir las cadenas a sus tipos de datos nativos. Por ejemplo, una columna que se compone de campos de fecha se puede convertir en una Fecha.

  • La opción columnas es para indicar si desea generar el registro en forma de objetos literales. De forma predeterminada, esta columna se establece en “falso” y el analizador genera los registros en forma de matrices. Si se establece en true, el analizador deducirá el nombre de la columna de la primera línea.

Finalmente, abrimos un flujo de lectura usando el módulo fs y comenzamos a canalizarlo al analizador.

Vamos a ejecutar este archivo:

1
$ node index.js

Esto resulta en:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
[
  {
    'Account Name': 'Cash',
    'Account Code': '101',
    Type: 'Assets',
    Description: 'Checking account balance'
  },
  {
    'Account Name': 'Wages Payable',
    'Account Code': '220',
    Type: 'Liabilities',
    Description: 'Amount owed to employes for hours not yet paid'
  },
  {
    'Account Name': 'Rent expense',
    'Account Code': '560',
    Type: 'Expenses',
    Description: 'Cost of occupied rented facilities during accounting period'
  }
]

En lugar de simplemente imprimir el contenido, puede manipular estos datos, construir objetos con la información de estos campos o guardarlos en una base de datos, por ejemplo.

Uso de la API de sincronización

Vamos a replicar esta funcionalidad usando la API de sincronización:

1
2
3
4
5
6
7
var fs = require('fs').promises;
var parse = require('csv-parse/lib/sync');
(async function () {
    const fileContent = await fs.readFile(__dirname+'/chart-of-accounts.csv');
    const records = parse(fileContent, {columns: true});
    console.log(records)
})();

Nuevamente, estamos importando el módulo fs y la API de sincronización del módulo csv-parse.

Luego, estamos creando una función async, en la que recuperamos el contenido del archivo esperando la respuesta de la función readFile().

Luego, podemos crear un parser que tome el contenido del archivo como primer argumento y un objeto literal como segundo. Este objeto literal contiene opciones para crear el analizador (hemos establecido columns en true). Este analizador está asignado a una variable constante y simplemente imprimimos su contenido por motivos de brevedad:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
[
  {
    'Account Name': 'Cash',
    'Account Code': '101',
    Type: 'Assets',
    Description: 'Checking account balance'
  },
  {
    'Account Name': 'Wages Payable',
    'Account Code': '220',
    Type: 'Liabilities',
    Description: 'Amount owed to employes for hours not yet paid'
  },
  {
    'Account Name': 'Rent expense',
    'Account Code': '560',
    Type: 'Expenses',
    Description: 'Cost of occupied rented facilities during accounting period'
  }
]

Escribir archivos CSV usando CSV Stringify

Similar a la lectura, a veces nos gustaría escribir datos en un formato CSV. Para esto, usaremos el paquete csv-stringify de la suite node-csv. Stringification solo significa que convertiremos algunos datos (JSON en nuestro ejemplo) en una cadena. Luego, esta cadena se escribe en un archivo, en formato CSV.

Supongamos que tiene algunos contenidos JSON que le gustaría escribir como un archivo CSV:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
var someData = [
    {
        "Country": "Nigeria",
        "Population": "200m",
        "Continent": "Africa",
        "Official Language(s)": "English"
    },
    {
        "Country": "India",
        "Population": "1b",
        "Continent": "Asia",
        "Official Language(s)": "Hindi, English"
    },
    {
        "Country": "United States of America",
        "Population": "328m",
        "Continent": "North America",
        "Official Language": "English"
    },
    {
        "Country": "United Kingdom",
        "Population": "66m",
        "Continent": "Europe",
        "Official Language": "English"
    },
    {
        "Country": "Brazil",
        "Population": "209m",
        "Continent": "South America",
        "Official Language": "Portugese"
    }
]

El paquete csv-stringify también tiene un par de opciones de API, sin embargo, la API de devolución de llamada ofrece una manera realmente simple de clasificar datos, sin la necesidad de manejar eventos como con la API de transmisión.

Avancemos y encadenemos los datos anteriores, antes de escribirlos en un archivo:

1
2
3
4
5
6
7
8
var fs = require('fs');
var stringify = require('csv-stringify');
    
stringify(someData, {
    header: true
}, function (err, output) {
    fs.writeFile(__dirname+'/someData.csv', output);
})

Aquí, estamos importando los módulos fs y csv-stringify. Luego, usando la función stringify(), proporcionamos los datos que nos gustaría convertir en una cadena. También proporcionamos un objeto literal que contiene la opción header. Finalmente, también hay una función de devolución de llamada que se usa para escribir el contenido en un archivo.

También están disponibles otras opciones como cast, columns y delimiter. En nuestro caso, estamos configurando la opción header en true para decirle al stringifier que genere los nombres de las columnas en el primer registro.

Ejecutar este código genera un archivo con el contenido adecuado:

escribiendo csv a un archivo en nodejs

Conclusión

El módulo node-csv es un conjunto de módulos más pequeños que se utilizan para leer/analizar, transformar y escribir datos CSV desde y hacia archivos.

Hemos usado el módulo csv-parse para leer archivos CSV y el módulo csv-stringify para encadenar datos antes de escribirlos en un archivo usando Node.js. s.