如何在Node.js中将CSV转换为JSON

93
我正试图将csv文件转换为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},
...

我尝试使用node-csv解析库,但输出结果像数组而不是我期望的形式。

我正在使用Node 0.8和express.js,并希望获得一个简单的建议来完成这个任务。


http://apievangelist.com/2013/09/24/excel-and-csv-conversion-to-json-and-xml-in-javascript-that-runs-100-on-github/ 和 http://kinlane.github.io/csv-converter/ 看起来很不错。 - VonC
我写了一篇小博客,介绍了与brnrd提出的类似解决方案:http://thinkingonthinking.com/scripting-a-csv-converter/ - poseid
21个回答

122

Node.js csvtojson模块是一款全面的nodejs csv解析器。它可以作为node.js应用程序库/命令行工具或浏览器使用(借助browserifywebpack)。

源代码可在此处找到。

它速度快,内存消耗低,但功能强大,支持丰富的API和易于阅读的文档,可满足各种解析需求。

详细的文档可以在此处找到。

以下是一些代码示例:

在您的Node.js应用程序中将其用作库(csvtojson@2.0.0 +):

  1. 通过npm安装它

npm install --save csvtojson@latest

  1. 在您的node.js应用程序中使用它:
// require csvtojson
var csv = require("csvtojson");

// Convert a csv file with csvtojson
csv()
  .fromFile(csvFilePath)
  .then(function(jsonArrayObj){ //when parse finished, result will be emitted here.
     console.log(jsonArrayObj); 
   })

// Parse large csv with stream / pipe (low mem consumption)
csv()
  .fromStream(readableStream)
  .subscribe(function(jsonObj){ //single json object will be emitted for each csv line
     // parse each json asynchronousely
     return new Promise(function(resolve,reject){
         asyncStoreToDb(json,function(){resolve()})
     })
  }) 

//Use async / await
const jsonArray=await csv().fromFile(filePath);

将其用作命令行工具:

sh# npm install csvtojson
sh# ./node_modules/csvtojson/bin/csvtojson ./youCsvFile.csv

-或-

sh# npm install -g csvtojson
sh# csvtojson ./yourCsvFile.csv

对于高级用法:

sh# csvtojson --help

你可以从上面的 Github 页面找到更多细节。


代码已添加。更详细的文档请查看此处:https://github.com/Keyang/node-csvtojson - Keyang
我不知道这是否只发生在我身上,但对于一个大型CSV文件,这太慢了。比d3慢10秒。 - limoragni
对于像我这样正在寻找从Web URL读取更简单版本的人,csv() .fromStream(request.get('https://example.com/test.csv')) .then((jsonArray) => { console.log(util.inspect(jsonArray)); }, (err)=>{ console.log(err); }); - Vikas Putcha
如果文件是由用户上传的呢?我有文件在 'file' 变量中,我想将其转换为 JSON。我该如何使用 csvtojson 包来实现? - Himanshu Tariyal
@HimanshuTariyal 在 var csv = require("csvtojson"); 下面添加这一行 const csvFilePath = <您的文件路径> - Green
显示剩余3条评论

24

你可以尝试使用underscore.js

首先,使用toArray函数将行转换为数组:

var letters = _.toArray(a,b,c,d);
var numbers = _.toArray(1,2,3,4);

然后使用object函数将数组对象结合起来:

var json = _.object(letters, numbers);

到那时,json变量应该包含类似以下内容:

{"a": 1,"b": 2,"c": 3,"d": 4}

21

我曾经做过类似的事情,希望这能帮到你。

// Node packages for file system
var fs = require('fs');
var path = require('path');


var filePath = path.join(__dirname, 'PATH_TO_CSV');
// Read CSV
var f = fs.readFileSync(filePath, {encoding: 'utf-8'}, 
    function(err){console.log(err);});

// Split on row
f = f.split("\n");

// Get first row for column headers
headers = f.shift().split(",");

var json = [];    
f.forEach(function(d){
    // Loop through each row
    tmp = {}
    row = d.split(",")
    for(var i = 0; i < headers.length; i++){
        tmp[headers[i]] = row[i];
    }
    // Add object to list
    json.push(tmp);
});

var outPath = path.join(__dirname, 'PATH_TO_JSON');
// Convert object to string, write json to file
fs.writeFileSync(outPath, JSON.stringify(json), 'utf8', 
    function(err){console.log(err);});

甚至可以这样写:var json = f.map(function(d, i){ ... return tmp; } - arve0
不幸的是,如果任何单元格中包含换行符,按换行符拆分将无法正常工作。 - Tobiah Rex
解决了90%的需求。 - Lakshman Pilaka
如果未来的读者需要支持换行符、逗号和带双引号字段的解决方案,请查看我的答案 https://dev59.com/TmQn5IYBdhLWcg3wcWzM#76019283 - Gabriel d'Agosto

13

这里有一个解决方案,不需要单独的模块。但它非常简陋,没有实现很多错误处理。它也可以使用更多的测试,但它可以让您开始。如果您要解析非常大的文件,您可能需要寻找其他替代方案。此外,请参见Ben Nadel的此解决方案

Node模块代码,csv2json.js:

/*
 * Convert a CSV String to JSON
 */
exports.convert = function(csvString) {
    var json = [];
    var csvArray = csvString.split("\n");

    // Remove the column names from csvArray into csvColumns.
    // Also replace single quote with double quote (JSON needs double).
    var csvColumns = JSON
            .parse("[" + csvArray.shift().replace(/'/g, '"') + "]");

    csvArray.forEach(function(csvRowString) {

        var csvRow = csvRowString.split(",");

        // Here we work on a single row.
        // Create an object with all of the csvColumns as keys.
        jsonRow = new Object();
        for ( var colNum = 0; colNum < csvRow.length; colNum++) {
            // Remove beginning and ending quotes since stringify will add them.
            var colData = csvRow[colNum].replace(/^['"]|['"]$/g, "");
            jsonRow[csvColumns[colNum]] = colData;
        }
        json.push(jsonRow);
    });

    return JSON.stringify(json);
};

Jasmine测试,csv2jsonSpec.js:

var csv2json = require('csv2json.js');

var CSV_STRING = "'col1','col2','col3'\n'1','2','3'\n'4','5','6'";
var JSON_STRING = '[{"col1":"1","col2":"2","col3":"3"},{"col1":"4","col2":"5","col3":"6"}]';

/* jasmine specs for csv2json */
describe('csv2json', function() {

    it('should convert a csv string to a json string.', function() {
        expect(csv2json.convert(CSV_STRING)).toEqual(
                JSON_STRING);
    });
});

这个不如csvtojson好用。当我有“Aug 23, 2016”时,它将aug23和2016拆分成不同的字段。 - MrWiLofDoom
糟糕。你可以用引号将日期括起来来修复它吗? - Jess

6

使用 ES6

const toJSON = csv => {
    const lines = csv.split('\n')
    const result = []
    const headers = lines[0].split(',')

    lines.map(l => {
        const obj = {}
        const line = l.split(',')

        headers.map((h, i) => {
            obj[h] = line[i]
        })

        result.push(obj)
    })

    return JSON.stringify(result)
}

const csv = `name,email,age
francis,francis@gmail.com,33
matty,mm@gmail.com,29`

const data = toJSON(csv)

console.log(data)

输出

// [{"name":"name","email":"email","age":"age"},{"name":"francis","email":"francis@gmail.com","age":"33"},{"name":"matty","email":"mm@gmail.com","age":"29"}]

你的代码存在内存泄漏问题。 - Sayf-Eddine

6
如果你只需要一个命令行转换器,对于我来说最快速、最干净的解决方案是使用csvtojsonnpx(在node.js中默认包含)。 $ npx csvtojson ./data.csv > data.json

5

使用 lodash

function csvToJson(csv) {
  const content = csv.split('\n');
  const header = content[0].split(',');
  return _.tail(content).map((row) => {
    return _.zipObject(header, row.split(','));
  });
}

1
一个小调整:我添加了.map(function(str) { return _.trim(str, '"')来删除标题和数据项中的任何双引号,例如 const header = content[0].split(',').map(function(str) { return _.trim(str, '"'); });return _.zipObject(header, row.split(',').map(function(str) { return _.trim(str, '"'); })); - CharlesA

3
我有一个非常简单的解决方案,可以使用csvtojson模块在控制台上打印JSON格式的CSV数据。
// require csvtojson
var csv = require("csvtojson");

const csvFilePath='customer-data.csv' //file path of csv
csv()
.fromFile(csvFilePath)``
.then((jsonObj)=>{
    console.log(jsonObj);
})

3
我开始使用 node-csvtojson,但它对我的链接带来了太多的依赖。
基于你的问题和 brnd 的答案,我使用了 node-csvunderscore.js 进行构建。
var attribs;
var json:
csv()
    .from.string(csvString)
    .transform(function(row) {
        if (!attribs) {
            attribs = row;
            return null;
        }
        return row;
     })
    .to.array(function(rows) {
        json = _.map(rows, function(row) {
            return _.object(attribs, row);
        });
     });

异步和下划线对你来说太难了吗? - Spencer
3
@Spencer,在我发布这篇文章的时候,依赖关系是不同的:https://github.com/Keyang/node-csvtojson/blob/288d1cca1b9f2864acd688d13217c68f3cef68f8/package.json 引入express进行csv转换感觉很不自然。 - xverges
哦,是的,那是一个疯狂的依赖关系。我的错。 - Spencer

3

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