【问题标题】:Large CSV to JSON/Object in Node.jsNode.js 中的大型 CSV 到 JSON/对象
【发布时间】:2026-01-07 21:45:01
【问题描述】:

我正在尝试做一些看起来不仅应该相当容易完成的事情,而且是一项足够常见的任务,可以使用简单的软件包来完成它。我希望获取一个大型 CSV 文件(从关系数据库表中导出)并将其转换为 JavaScript 对象数组。此外,我想将其导出到.json 文件装置。

CSV 示例:

a,b,c,d
1,2,3,4
5,6,7,8
...

所需的 JSON:

[
{"a": 1,"b": 2,"c": 3,"d": 4},
{"a": 5,"b": 6,"c": 7,"d": 8},
...
]

我已经尝试了几个节点 CSV 解析器、流媒体、自称 CSV-to-JSON 库,但我似乎无法得到我想要的结果,或者如果我能的话,它只有在文件较小的情况下才有效。我的文件大小接近 1 GB,行数约为 40m(这将创建 40m 个对象)。我希望它需要流式传输输入和/或输出以避免内存问题。

这是我尝试过的包:

我正在使用 Node 0.10.6,希望获得有关如何轻松完成此任务的建议。滚动我自己的可能是最好的,但我不确定从哪里开始使用 Node 的所有流功能,特别是因为它们在 0.10.x 中更改了 API。

【问题讨论】:

  • 您确定您没有忘记删除“所需的 JSON”部分中的一些大括号吗?不应该是{"a": 1, "b": 2, "c": 3, "d": 4},吗?
  • 糟糕,谢谢。已编辑。

标签: javascript json node.js csv


【解决方案1】:

检查 node.js csvtojson 模块,该模块可用作库、命令行工具或 Web 服务器插件。 https://www.npmjs.org/package/csvtojson。 源代码可以在以下位置找到: https://github.com/Keyang/node-csvtojson

或从 NPM 仓库安装:

npm install -g csvtojson

它支持任何大小的csv数据/字段类型/嵌套json等。一堆功能。

例子

var Converter=require("csvtojson").core.Converter;

var csvConverter=new Converter({constructResult:false, toArrayString:true}); // The constructResult parameter=false will turn off final result construction in memory for stream feature. toArrayString will stream out a normal JSON array object.

var readStream=require("fs").createReadStream("inputData.csv"); 

var writeStream=require("fs").createWriteStream("outpuData.json");

readStream.pipe(csvConverter).pipe(writeStream);

您也可以将其用作 cli 工具:

csvtojson myCSVFile.csv

【讨论】:

    【解决方案2】:

    虽然这远不是​​一个完整的答案,但您可以将您的解决方案基于 https://github.com/dominictarr/event-stream 。改编自自述文件的示例:

        var es = require('event-stream')
        es.pipeline(                         //connect streams together with `pipe`
          process.openStdin(),              //open stdin
          es.split(),                       //split stream to break on newlines
          es.map(function (data, callback) { //turn this async function into a stream
            callback(null
              , JSON.stringify(parseCSVLine(data)))  // deal with one line of CSV data
          }), 
          process.stdout
          )
    

    在那之后,我希望你在每一行都有一堆字符串化的 JSON 对象。 然后需要将其转换为一个数组,您可以使用它并将, 附加到每行的末尾,在最后一行删除它,然后将[] 添加到开头和结尾文件。

    parseCSVLine 函数必须配置为将 CSV 值分配给正确的对象属性。通过文件的第一行后,这可以相当容易地完成。

    我确实注意到该库未在 0.10 上进行测试(至少没有使用 Travis),所以要小心。也许自己在源上运行npm test

    【讨论】:

    • 谢谢。我一直在尝试event-stream,但是当它到达es.map 时一直失败。我会坚持下去,希望能解决。
    • 我自己没有使用过事件流。也许看看示例代码的测试?
    • es.split() 可能不足以按行拆分 CSV。根据rfc-editor.org/rfc/rfc4180.txt,如果在双引号内,换行符可以是值的一部分。
    【解决方案3】:

    我找到了一种更简单的方法来使用 csvtojson 读取 csv 数据。

    代码如下:

    var Converter = require("csvtojson").Converter;
    var converter = new Converter({});
    converter.fromFile("sample.csv",function(err,result){
      var csvData = JSON.stringify
      ([
        {resultdata : result[0]},
        {resultdata : result[1]},
        {resultdata : result[2]},
        {resultdata : result[3]},
        {resultdata : result[4]}
      ]);
      csvData = JSON.parse(csvData);
      console.log(csvData);
    });

    或者您可以轻松地做到这一点:

    var Converter = require("csvtojson").Converter;
    var converter = new Converter({});
    converter.fromFile("sample.csv",function(err,result){ 
      console.log(result);
    });

    这是第一个代码的结果:

    [ { resultdata: 
         { 'Header 1': 'A_1',
           'Header 2': 'B_1',
           'Header 3': 'C_1',
           'Header 4': 'D_1',
           'Header 5': 'E_1' } },
      { resultdata: 
         { 'Header 1': 'A_2',
           'Header 2': 'B_2',
           'Header 3': 'C_2',
           'Header 4': 'D_2',
           'Header 5': 'E_2' } },
      { resultdata: 
         { 'Header 1': 'A_3',
           'Header 2': 'B_3',
           'Header 3': 'C_3',
           'Header 4': 'D_3',
           'Header 5': 'E_3' } },
      { resultdata: 
         { 'Header 1': 'A_4',
           'Header 2': 'B_4',
           'Header 3': 'C_4',
           'Header 4': 'D_4',
           'Header 5': 'E_4' } },
      { resultdata: 
         { 'Header 1': 'A_5',
           'Header 2': 'B_5',
           'Header 3': 'C_5',
           'Header 4': 'D_5',
           'Header 5': 'E_5' } } ]

    此代码的来源位于: https://www.npmjs.com/package/csvtojson#installation

    希望你有所了解。

    【讨论】:

      【解决方案4】:

      我建议您自己实现逻辑。 Node.js 实际上非常擅长这类任务。

      以下解决方案使用流,因为它们不会占用您的内存。

      安装依赖项

      npm install through2 split2 --save
      

      代码

      import through2 from 'through2'
      import split2 from 'split2'
      
      fs.createReadStream('<yourFilePath>')
        // Read line by line
        .pipe(split2())
        // Parse CSV line
        .pipe(parseCSV()) 
        // Process your Records
        .pipe(processRecord()) 
      
      const parseCSV = () => {
        let templateKeys = []
        let parseHeadline = true
        return through2.obj((data, enc, cb) => {
          if (parseHeadline) {
            templateKeys = data
              .toString()
              .split(';')
            parseHeadline = false
            return cb(null, null)
          }
          const entries = data
            .toString()
            .split(';')
          const obj = {}
          templateKeys.forEach((el, index) => {
            obj[el] = entries[index]
          })
          return cb(null, obj)
        })
      }
      
      const processRecord = () => {
        return through2.obj(function (data, enc, cb) {
          // Implement your own processing 
          // logic here e.g.:
          MyDB
            .insert(data)
            .then(() => cb())
            .catch(cb)
        })
      }
      

      有关此主题的更多信息,请访问 Stefan Baumgartners 优秀tutorial 关于此主题。

      【讨论】:

        【解决方案5】:

        您可以使用流来处理大文件。 这是您需要做的。这应该可以正常工作。

        npm i --save csv2json fs-extra // install the modules
        
        const csv2json = require('csv2json');
        const fs = require('fs-extra');
        
        const source = fs.createReadStream(__dirname + '/data.csv');
        const output = fs.createWriteStream(__dirname + '/result.json');
         source
           .pipe(csv2json())
           .pipe(output );
        

        【讨论】:

          【解决方案6】:

          嗯...很多解决方案,我会添加一个scramjet

          $ npm install --save scramjet
          

          然后

          process.stdin.pipe(
              new (require("scramjet").StringStream)("utf-8")
          )
              .CSVParse()
              .toJSONArray()
              .pipe(process.stdout)
          

          这将导致您以流式方式描述的内容。

          【讨论】: