Javascript 将csv解析输出保存到变量
我不熟悉使用csv解析,这个来自项目github的示例可以满足我的需要,但有一个例外。我希望将数据存储在变量中,而不是通过console.log输出。我曾尝试将fs行赋给一个变量,然后返回Javascript 将csv解析输出保存到变量,javascript,node.js,Javascript,Node.js,我不熟悉使用csv解析,这个来自项目github的示例可以满足我的需要,但有一个例外。我希望将数据存储在变量中,而不是通过console.log输出。我曾尝试将fs行赋给一个变量,然后返回数据,而不是记录它,但这只是返回了一大堆我不理解的东西。最终目标是将CSV文件导入SQLite var fs = require('fs'); var parse = require('..'); var parser = parse({delimiter: ';'}, function(err, data)
数据
,而不是记录它,但这只是返回了一大堆我不理解的东西。最终目标是将CSV文件导入SQLite
var fs = require('fs');
var parse = require('..');
var parser = parse({delimiter: ';'}, function(err, data){
console.log(data);
});
fs.createReadStream(__dirname+'/fs_read.csv').pipe(parser);
以下是我尝试过的:
const fs = require("fs");
const parse = require("./node_modules/csv-parse");
const sqlite3 = require("sqlite3");
// const db = new sqlite3.Database("testing.sqlite");
let parser = parse({delimiter: ","}, (err, data) => {
// console.log(data);
return data;
});
const output = fs.createReadStream(__dirname + "/users.csv").pipe(parser);
console.log(output);
这是一个让人对异步流API感到困惑的问题,似乎至少要问三件事
输出
以包含表示已解析CSV数据的数组输出将永远不会像您(和许多其他程序员)所希望的那样存在于顶级。所有整齐地组合在一个地方的数据只能存在于回调函数中。从语法上来说,下一个最好的方法是const output=wait somePromiseOfOutput()
,但这只能发生在异步函数中,并且只有在我们从流切换到承诺时才会发生。这一切都是可能的,我提到这一点是为了让你以后可以自己查看。我假设你想坚持使用streams
只有在读取整个流之后,才能存在由所有行组成的数组。这就是为什么在作者的“Stream API”示例中,所有行仅在.on('end',…)
回调中可用的原因。如果您想对同时存在的所有行执行任何操作,则需要在结束回调中执行
请注意,作者:
使用on-readable回调将单个记录推入以前在外部定义的空数组,该数组名为output
李>
使用on error回调来报告错误
使用on-end回调将输出中的所有累积记录与预期结果进行比较
...
常量输出=[]
...
on('readable',function(){
记录
while(record=parser.read()){
输出推送(记录)
}
})
//抓住任何错误
parser.on('error',函数(err){
控制台错误(错误消息)
})
//完成后,测试解析的输出是否符合预期
on('end',function(){
主张平等(
产出,
[
['root'、'x'、'0'、'0'、'root'、'/root'、'/bin/bash'],
['someone'、'x'、'1022'、'1022'、''、'/home/someone'、'/bin/bash']
]
)
})
至于与sqlite接口的目标,这实质上是构建一个定制的流端点李>
在这个用例中,它接受解析器的输出并将行发送到数据库
然后,您只需将管道调用链接为
fs.createReadStream(uu dirname+'/fs_read.csv')
.pipe(解析器)
.pipe(您的\u可写\u流)
小心:此代码立即返回。它不会等待操作完成。它与node.js内部的隐藏事件循环交互。事件循环经常使来自另一种语言、习惯于更命令式风格的新开发人员感到困惑,并跳过了node.js培训的这一部分
实现这样一个定制的可写流可能会变得复杂,留给读者作为练习。如果解析器发出一行,那么编写器就可以处理单行,这将是最简单的。确保您能够以某种方式注意到错误并抛出适当的异常,否则您将被诅咒,结果不完整,没有警告或原因
用一个自定义函数writeRowToSqlite(data)
替换let parser=…
中的console.log(data)
,您无论如何都必须编写该函数才能实现自定义流。由于异步API问题,使用返回数据
没有任何用处。正如您所看到的,它当然无法将数据放入输出变量
至于为什么修改后的帖子中的输出不包含数据
不幸的是,正如您所发现的,这通常是错误的:
const output=fs.createReadStream(uu dirname+“/users.csv”).pipe(解析器);
控制台日志(输出);
这里,变量输出将是a,它与可读流中包含的数据不同。简单地说,这就像文件系统中有一个文件一样,您可以获取有关该文件的各种系统信息,但文件中包含的内容是通过不同的调用访问的 我也在努力找出如何将数据从csv解析返回到调用解析的顶层。具体地说,我试图在处理结束时获取parser.info数据,以查看是否成功,但如果需要,解决方案也可以用于获取行数据
关键是将所有流事件侦听器包装成一个承诺,并在解析器的回调中解析该承诺
function startFileImport(myFile) {
// THIS IS THE WRAPPER YOU NEED
return new Promise((resolve, reject) => {
let readStream = fs.createReadStream(myFile);
let fileRows = [];
const parser = parse({
delimiter: ','
});
// Use the readable stream api
parser.on('readable', function () {
let record
while (record = parser.read()) {
if (record) { fileRows.push(record); }
}
});
// Catch any error
parser.on('error', function (err) {
console.error(err.message)
});
parser.on('end', function () {
const { lines } = parser.info;
// RESOLVE OUTPUT THAT YOU WANT AT PARENT-LEVEL
resolve({ status: 'Successfully processed lines: ', lines });
});
// This will wait until we know the readable stream is actually valid before piping
readStream.on('open', function () {
// This just pipes the read stream to the response object (which goes to the client)
readStream.pipe(parser);
});
// This catches any errors that happen while creating the readable stream (usually invalid names)
readStream.on('error', function (err) {
resolve({ status: null, error: 'readStream error' + err });
});
});
}
如果您的目标只是将一个csv文件导入sqlite,那么您可以放弃node.js,直接从sqlite使用。您还可以从node.js生成一个进程,该进程将运行一个shell脚本并执行导入过程。这比我预期的答案要多得多!谢谢:)看来我有很多书要读。谁会想到这么简单的概念会变得如此困难?我想我会同意你在原始帖子中的建议,只是为了让我振作起来。我将此标记为答案,因为它回答了我的问题。再次感谢。