Большой CSV для JSON/Object в Node.js
Я пытаюсь сделать что-то похожее на то, что это должно быть не только достаточно простым, но достаточно общей задачей, чтобы для этого были доступны простые пакеты. Я хочу взять большой 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},
...
]
Я пробовал несколько парсеров node CSV, стримеров, самопровозглашенных библиотек CSV-to-JSON, но я не могу получить результат, который я хочу, или если я могу его использовать, только если файлы меньше. Размер моего файла составляет около 1 ГБ с ~ 40 м строк (что создало бы 40 м объектов). Я ожидаю, что для предотвращения проблем с памятью потребуется потоковая передача ввода и/или вывода.
Вот пакеты, которые я пробовал:
Я использую node 0.10.6 и хочу получить рекомендацию о том, как легко выполнить это. Возможно, мой собственный вариант может быть лучшим, но я не уверен, с чего начать все функции потоковой передачи node, тем более, что они изменили API в 0.10.x.
Ответы
Ответ 1
Хотя это далеко не полный ответ, вы можете найти свое решение на https://github.com/dominictarr/event-stream. Адаптированный пример из файла readme:
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
в источнике.
Ответ 2
Проверьте модуль node.js csvtojson, который можно использовать в качестве библиотеки, инструментов командной строки или плагина веб-сервера. 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
Ответ 3
Я нашел что-то более легкое для чтения 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);
});
Ответ 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, отличный учебник на эту тему.