在Node.js中写入CSV文件

66

我正在苦苦寻找一种在 Node.js 中将数据写入 CSV的方法。

虽然有几个CSV插件可用,但它们只能将数据'写入'标准输出(stdout)。

理想情况下,我想使用循环逐行编写数据。


2
“然而,它们只会将内容“写入”到标准输出(stdout)。”这似乎非常令人惊讶。它们不会将内容写入任何可写的流(Stream),必须是stdout吗?! - T.J. Crowder
你能否包含你已经测试过的模块链接,这样其他人就可以审查它们和/或知道哪些替代方案可以建议? - Joe White
1
有一个使用Node.js生成CSV的教程。http://programmerblog.net/generate-csv-using-nodejs/ - Maz I
9个回答

55

35

node-csv-parser的文档明确指出它可以与流(请参见fromStreamtoStream)一起使用,并没有硬编码使用stdout。

当你在npm search csv时,还有其他几个CSV解析器也会出现--您可能也想看看它们。


28

这里是一个简单的示例,使用csv-stringify将内存中的数据集写入CSV文件,使用fs.writeFile

import stringify from 'csv-stringify';
import fs from 'fs';

let data = [];
let columns = {
  id: 'id',
  name: 'Name'
};

for (var i = 0; i < 10; i++) {
  data.push([i, 'Name ' + i]);
}

stringify(data, { header: true, columns: columns }, (err, output) => {
  if (err) throw err;
  fs.writeFile('my.csv', output, (err) => {
    if (err) throw err;
    console.log('my.csv saved.');
  });
});

这里与John的解决方案相比有什么优势?确保写入的是“string”? - Timo
这个解决方案帮助了我。我需要与JSON字段名不同的列名。将列定义为该对象解决了问题。 - GoForth

23

如果您想像您所说的那样使用循环,可以通过Node fs执行以下操作:

let fs = require("fs")

let writeStream = fs.createWriteStream('/path/filename.csv')

someArrayOfObjects.forEach((someObject, index) => {     
    let newLine = []
    newLine.push(someObject.stringPropertyOne)
    newLine.push(someObject.stringPropertyTwo)
    ....

    writeStream.write(newLine.join(',')+ '\n', () => {
        // a line was written to stream
    })
})

writeStream.end()

writeStream.on('finish', () => {
    console.log('finish write stream, moving along')
}).on('error', (err) => {
    console.log(err)
})

6

如果你不想使用除fs之外的任何库,你可以手动完成。

let fileString = ""
let separator = ","
let fileType = "csv"
let file = `fileExample.${fileType}`

Object.keys(jsonObject[0]).forEach(value=>fileString += `${value}${separator}`)
    fileString = fileString.slice(0, -1)
    fileString += "\n"

    jsonObject.forEach(transaction=>{
        Object.values(transaction).forEach(value=>fileString += `${value}${separator}`)
        fileString = fileString.slice(0, -1)
        fileString += "\n"
    })

fs.writeFileSync(file, fileString, 'utf8')

3

编写CSV非常容易,而且可以在不使用库的情况下完成。

import { writeFile } from 'fs/promises';
// you can use just fs module too

// Let's say you want to print a list of users to a CSV
const users = [
  { id: 1, name: 'John Doe0', age: 21 },
  { id: 2, name: 'John Doe1', age: 22 },
  { id: 3, name: 'John Doe2', age: 23 }
];

// CSV is formatted in the following format 
/*
  column1, column2, column3
  value1, value2, value3
  value1, value2, value
*/
// which we can do easily by
const dataCSV = users.reduce((acc, user) => {
    acc += `${user.id}, ${user.name}, ${user.age}\n`;
    return acc;
  }, 
  `id, name, age\n` // column names for csv
);

// finally, write csv content to a file using Node's fs module
writeFile('mycsv.csv', dataCSV, 'utf8')
  .then(() => // handle success)
  .catch((error) => // handle error)

注意:如果您的CSV内容中有,,则必须对其进行转义或使用其他分隔符。如果是这种情况,我建议使用类似csv-stringify的库。


很好,它运行得很好,但是它只写入一行数据。 如何将多行附加到此文件中,但仅写入标题行一次。 - abdp
reduce 正在做这件事,您在映射 CSV 数据时一定出了问题。 - Haseeb Anwar

1

如果您不想使用除fs以外的任何库,您可以手动完成。此外,您可以按照自己的要求过滤数据以便写入CSV文件。

router.get('/apiname', (req, res) => {
 const data = arrayOfObject; // you will get from somewhere
 /*
    // Modify old data (New Key Names)
    let modifiedData = data.map(({ oldKey1: newKey1, oldKey2: newKey2, ...rest }) => ({ newKey1, newKey2, ...rest }));
 */
 const path = './test'
 writeToFile(path, data, (result) => {
     // get the result from callback and process
     console.log(result) // success or error
   });
});

writeToFile = (path, data, callback) => {
    fs.writeFile(path, JSON.stringify(data, null, 2), (err) => { // JSON.stringify(data, null, 2) help you to write the data line by line
            if (!err) {
                callback('success');
                // successfull
            }
            else {
                 callback('error');
               // some error (catch this error)
            }
        });
}

1
对于那些更喜欢 fast-csv的人:
const { writeToPath } = require('@fast-csv/format');

const path = `${__dirname}/people.csv`;
const data = [{ name: 'Stevie', id: 10 }, { name: 'Ray', id: 20 }];
const options = { headers: true, quoteColumns: true };

writeToPath(path, data, options)
        .on('error', err => console.error(err))
        .on('finish', () => console.log('Done writing.'));

-1

这是在 Nest.js 中对我有效的代码

import { Parser } from "json2csv";

 const csv = require('csvtojson');

      const csvFilePath = process.cwd() + '/' + file.path;

      let csv data  = await csv().fromFile(csvFilePath); /// read data from csv into an array of json 
          


/// * from here how to write data into csv *


          data.push({
                label: value,
                .......
          })                 
        }

        const fields = [
         'field1','field2', ... 
        ]
        
        const parser = new Parser({ fields, header:false }); /// if dont want header else remove header: false
        const csv = parser.parse(data);
        appendFileSync('./filename.csv',`${csv}\n`); // remove /n if you dont want new line at the end 
      

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接