15

我正在尝试做一些看起来不仅应该相当容易完成的事情,而且是一项足够常见的任务,可以使用简单的软件包来完成它。我希望获取一个大型 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。

4

6 回答 6

8

检查 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
于 2013-06-19T13:13:36.270 回答
3

虽然这远不是​​一个完整的答案,但您可以将您的解决方案基于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 对象。然后需要将其转换为一个数组,您可以使用该数组并将其附加,到每一行的末尾,在最后一行将其删除,然后将[and添加]到文件的开头和结尾。

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

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

于 2013-05-17T20:56:26.873 回答
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

我希望你有一些想法。

于 2016-03-04T03:58:31.020 回答
1

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

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 );
于 2018-04-16T09:49:42.530 回答
1

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

于 2017-04-25T14:02:46.883 回答
0

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

$ npm install --save scramjet

接着

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

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

于 2018-04-25T20:40:41.063 回答