使用Node.js读写CSV文件

Reading and Writing CSV Files with Node.js

介绍

术语CSV是表示逗号分隔值的缩写。

CSV文件是纯文本文件,其中包含根据CSV标准设置格式的数据。 它具有代表记录的不同行,并且记录中的每个字段都用逗号分隔。

将表格数据存储在CSV中非常方便:

1
2
3
4
Name,Surname,Age,Gender
John,Snow,26,M
Clair,White,33,F
Fancy,Brown,78,F

在这里,第一行代表我们的CSV记录的列/字段的标题,然后有3条记录代表某些人。 如您所见,这些值由逗号分隔,并且每个记录都从新行开始。

嘿,但是,如果我们想对以CSV格式存储的某些字段添加逗号或换行符,该怎么办?

有几种解决此问题的方法,例如,我们可以将这些值用双引号引起来。 但是,某些CVS实现在设计上不支持此功能。

CSV标准化

RFC4180中描述了最常用的CSV标准之一。

据此,CSV格式由以下7条规则描述:

  • 每个记录位于单独的行上,并由换行符(CRLF)分隔。

  • 文件中的最后一条记录可能有也可能没有换行符。

  • 可能有一个可选的标题行显示为文件的第一行,其格式与普通记录行相同。此标头将包含与文件中的字段相对应的名称,并且应包含与文件其余部分中的记录相同的字段数(应通过此标头的可选" header"参数指示标头行的存在或不存在) MIME类型)。

  • 在标题和每个记录中,可能会有一个或多个字段,以逗号分隔。每行应在整个文件中包含相同数量的字段。空格被视为字段的一部分,不应忽略。记录中的最后一个字段不得在逗号后跟。

  • 每个字段可能会或可能不会用双引号引起来(但是某些程序(例如Microsoft Excel)根本不使用双引号)。如果字段没有用双引号引起来,则双引号可能不会出现在字段内。

  • 包含换行符(CRLF),双引号和逗号的字段应用双引号引起来。

  • 如果使用双引号将字段括起来,则必须在字段内部出现的双引号前面加上另一个双引号,以对其进行转义。

  • 如果您想阅读更多有关多个示例的内容,可以研究上面链接的原始RFC4180文档。

    在Node.js中读取CSV文件

    要在Node.js中读取CSV文件,我们只能使用fs模块,因为本质上CSV文件是纯文本文件。

    如果您有兴趣阅读有关使用Node.js读取文件或使用Node.js写入文件的更多信息,我们将涵盖全部内容!

    但是,有几个有用的模块可以为我们处理生成或解析CSV内容。 我们将从安装模块csv-parser开始:

    1
    $ npm i -s csv-parser

    然后,让我们将文章开头的CSV数据放到一个名为" data.csv"的文件中,然后再举一个非常简单的示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    const csv = require('csv-parser');
    const fs = require('fs');

    fs.createReadStream('data.csv')
      .pipe(csv())
      .on('data', (row) => {
        console.log(row);
      })
      .on('end', () => {
        console.log('CSV file successfully processed');
      });

    在这里,我们使用fs模块创建一个readStream,将其通过管道传输到csv对象,然后在每次处理CSV文件中的新行时将触发data事件。 当处理了CSV文件中的所有行时,会触发end事件,我们将一条短消息记录到控制台以表明这一点。

    出于演示目的,我们只对每个处理的行进行console.log,在运行代码之后,您将在控制台中看到以下输出:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    Row {
      Name: 'John',
      'Surname': 'Snow',
      'Age': '26',
      'Gender': 'M' }
    Row {
      Name: 'Clair',
      'Surname': 'White',
      'Age': '33',
      'Gender': 'F' }
    Row {
      Name: 'Fancy',
      'Surname': 'Brown',
      'Age': '78',
      'Gender': 'F' }
    CSV file successfully processed

    在Node.js中编写CSV文件

    记住CSV文件只是纯文本文件这一事实,我们总是可以限制自己仅使用本机fs模块,但是为了使我们的生活更轻松,我们将使用另一个常见的npm模块csv-writer

    首先去安装:

    1
    $ npm i -s csv-writer

    然后,代码:

    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
    33
    const createCsvWriter = require('csv-writer').createObjectCsvWriter;
    const csvWriter = createCsvWriter({
      path: 'out.csv',
      header: [
        {id: 'name', title: 'Name'},
        {id: 'surname', title: 'Surname'},
        {id: 'age', title: 'Age'},
        {id: 'gender', title: 'Gender'},
      ]
    });

    const data = [
      {
        name: 'John',
        surname: 'Snow',
        age: 26,
        gender: 'M'
      }, {
        name: 'Clair',
        surname: 'White',
        age: 33,
        gender: 'F',
      }, {
        name: 'Fancy',
        surname: 'Brown',
        age: 78,
        gender: 'F'
      }
    ];

    csvWriter
      .writeRecords(data)
      .then(()=> console.log('The CSV file was written successfully'));

    csv-writer模块需要一个初始配置,在此我们为其提供生成的CSV文件的名称和header配置。

    注意:在我们的JavaScript对象中,所有属性均为小写,但在CSV文件中,应将其首字母大写。

    配置完成后,我们需要做的就是调用writeRecords函数,传入data数组,该数组表示应写入CSV文件的数据结构。

    完成此过程后,我们将向控制台打印一条信息性消息,指出程序已完成。

    使用快速csv模块

    Node.js生态系统和npm提供了许多读取和写入CSV文件的选项。 我们将展示另一个流行的CSV模块的示例,并介绍如何使用fast-csv模块作为替代方法来写入数据数组。

    首先,我们必须安装模块:

    1
    $ npm i -s fast-csv

    1
    2
    3
    4
    5
    6
    const fastcsv = require('fast-csv');
    const fs = require('fs');
    const ws = fs.createWriteStream("out.csv");
    fastcsv
      .write(data, { headers: true })
      .pipe(ws);

    API有所不同,但结果是相同的。 在短短的几行代码中,我们设法将JavaScript对象数组写入CSV文件,以后可以由其他各种应用程序使用。

    结论

    使用Node.js读写CSV文件是一项常见的开发任务,因为CSV格式通常用于存储结构化表格数据。 许多npm模块都提供了此功能,因此您应该选择最适合您的需求并具有持续支持的模块。