使用node-csv在Node.js中读写CSV文件

Reading and Writing CSV Files in Node.js with node-csv

介绍

常见的开发任务是从文件读取数据。 常见的文件格式是.csv格式。

虽然您可以使用Node随附的fs模块读取CSV文件并获取文件的内容,但在大多数情况下,借助专门用于此目的的模块,解析和进一步转换要容易得多。

多个模块提供了诸如neat-csvcsv-parser包之类的功能。 但是,在本文中,我们将使用node-csv-一套CSV软件包,用于生成,解析,转换和字符串化CSV数据。

安装node-csv

该模块由csv-generatecsv-parsecsv-transformcsv-stringify软件包组成。

如果您不需要全部套件,则可以逐个安装整个套件或每个套件。 让我们使用默认设置初始化一个Node项目:

1
$ npm init -y

然后,让我们安装整个node-csv套件:

1
$ npm install node-csv

我们将使用包含以下内容的CSV文件:

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

使用csv-parse读取CSV文件

要读取CSV文件,我们将使用node-csv中的csv-parse包。

csv-parse包提供了多种解析CSV文件的方法-使用回调,流+回调以及Sync和async API。 我们将介绍流+回调API和Sync API。

流+回调API

让我们创建一个名为index.js的文件并构造一个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);

首先,我们导入本机文件系统模块(fs)和csv-parse模块。 然后,我们创建一个parser,它接受一个对象文字,其中包含我们要设置的选项。 第二个参数是用于访问记录的回调函数-在本例中,就是将其打印出来。

我们可以设置的选项不是强制性的。 在大多数情况下,您将使用任何delimitercastcolumns选项:

  • 分隔符选项默认为逗号,。 如果您要解析的文件中的数据使用其他定界符(例如分号;或管道|),则可以使用此选项进行指定。

    分隔符选项默认为逗号,。 如果您要解析的文件中的数据使用其他定界符(例如分号;或管道|),则可以使用此选项进行指定。

    强制转换选项默认为false,用于指示您是否要将字符串强制转换为其本地数据类型。 例如,由日期字段组成的列可以转换为Date

    columns选项用于指示是否要以对象文字形式生成记录。 默认情况下,此列设置为false,解析器以数组形式生成记录。 如果设置为true,则解析器将从第一行推断出列名。

    最后,我们使用fs模块打开了一个读取流,并开始将其传输到解析器中。

    让我们运行这个文件:

    1
    $ node index.js

    结果是:

    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'
      }
    ]

    例如,您可以操纵这些数据,使用这些字段中的信息构造对象,或者将它们保存到数据库中,而不仅仅是打印内容。

    使用同步API

    让我们使用Sync API复制此功能:

    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)
    })();

    同样,我们从csv-parse模块导入fs模块和Sync API。

    然后,我们创建一个async函数,在其中我们通过awaitreadFile()函数的响应来检索文件的内容。

    然后,我们可以创建一个parser,它将文件内容作为第一个参数,将对象文字作为第二个参数。 该对象文字包含用于创建解析器的选项(我们将columns设置为true)。 将此解析器分配给一个常量变量,为简便起见,我们仅将其内容打印出来:

    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'
      }
    ]

    使用CSV Stringify写入CSV文件

    与读取类似,有时我们希望将数据写成CSV格式。 为此,我们将使用node-csv套件中的csv-stringify包。 字符串化只是意味着我们将一些数据(在我们的示例中为JSON)转换为字符串。 然后将此字符串以CSV格式写入文件。

    假设您有一些想要以CSV文件形式记录的JSON内容:

    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"
        }
    ]

    尽管csv-stringify包也有几个API选项,但Callback API提供了一种非常简单的方式来对数据进行字符串化,而无需像Stream API一样处理事件。

    在将其写入文件之前,让我们继续对上面的数据进行字符串化:

    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);
    })

    在这里,我们要导入fscsv-stringify模块。 然后,使用stringify()函数,提供要转换为字符串的数据。 我们还提供了包含header选项的对象文字。 最后,还有一个回调函数,用于将内容写到文件中。

    其他选项,例如castcolumnsdelimiter也可用。 在我们的例子中,我们将header选项设置为true,以告诉字符串化器在第一条记录中生成列名。

    运行此代码将生成具有正确内容的文件:

    writing csv to a file in nodejs

    结论

    node-csv模块是一组较小的模块,用于从文件读取/解析,转换和写入CSV数据。

    在使用Node.js将数据写入文件之前,我们已经使用csv-parse模块读取CSV文件,并使用csv-stringify模块对数据进行字符串化。