Large CSV to JSON/Object in Node.js

Large CSV to JSON/Object in Node.js

本文关键字:in Node js Object CSV to JSON Large      更新时间:2023-09-26

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

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解析器,streamer,自称CSV到json库,但我似乎无法得到我想要的结果,或者如果我可以,它只能在文件较小的情况下工作。我的文件大小接近1 GB,有大约40m行(这将创建40m个对象)。我希望它需要流式输入和/或输出以避免内存问题。

以下是我尝试过的软件包:

  • https://github.com/klaemo/csv-stream
  • https://github.com/koles/ya-csv
  • https://github.com/davidgtonge/stream-convert(工作,但它是这样非常慢,因为我经常更改数据集。解析一个60 MB的csv文件花了将近3个小时)
  • https://github.com/cgiffard/CSVtoJSON.js
  • https://github.com/wdavidw/node-csv-parser(似乎不是设计用于将csv转换为其他格式)
  • https://github.com/voodootikigod/node-csv

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

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

或从NPM repo安装:

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

虽然这远远不是一个完整的答案,但您可以基于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

我发现了一些更简单的方法来读取csv数据使用csvtojson

代码如下:

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安装

我希望你有一些想法

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

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

我建议您自己实现这个逻辑。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 baumgartner关于此主题的优秀教程。

嗯…很多解决方案,我将添加一个scramjet:

$ npm install --save scramjet

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