[英]Save csv-parse output to a variable
我是使用 csv-parse 的新手,這個來自項目 github 的示例滿足了我的需求,但有一個例外。 我想將數據存儲在變量中,而不是通過 console.log 輸出。 我試過將 fs 行分配給一個變量,然后返回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);
我也在努力弄清楚如何將數據從 csv-parse 返回到調用解析的頂層。 具體來說,我試圖在處理結束時獲取 parser.info 數據以查看它是否成功,但是如果需要,該解決方案也可以用於獲取行數據。
關鍵是將所有流事件偵聽器包裝到一個 Promise 中,並在解析器的回調中解析 Promise。
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 });
});
});
}
這是一個讓人對異步流API感到困惑的問題,似乎至少要問三件事。
output
? 就像您(和許多其他程序員)希望的那樣,由於異步API的運行方式,該output
將永遠不會像您(和其他許多程序員)所希望的那樣存在於頂層。 整齊地組裝在一個地方的所有數據只能存在於回調函數中。 從語法const output = await somePromiseOfOutput()
,下一個最好的事情是const output = await somePromiseOfOutput()
但這只能在async function
發生,並且僅當我們從流切換到const output = await somePromiseOfOutput()
時才發生。 這都是可能的,我提到了它,因此您以后可以自己檢查出來。 我假設您要堅持使用流。
由所有行組成的數組只能在讀取整個流之后存在。 這就是為什么所有行僅在作者的“ Stream API”示例中僅在.on('end', ...)
回調中可用的原因。 如果您想同時處理所有存在的行,則需要在end回調中進行。
從https://csv.js.org/parse/api/注意到作者:
output
空數組。 ... const output = [] ... parser.on('readable', function(){ let record while (record = parser.read()) { output.push(record) } }) // Catch any error parser.on('error', function(err){ console.error(err.message) }) // When we are done, test that the parsed output matched what expected parser.on('end', function(){ assert.deepEqual( output, [ [ 'root','x','0','0','root','/root','/bin/bash' ], [ 'someone','x','1022','1022','','/home/someone','/bin/bash' ] ] ) })
在此用例中, 實現定制的可寫流 ,該流將接受解析器的輸出並將行發送到數據庫。
然后您只需將管道調用鏈接為
fs.createReadStream(__dirname+'/fs_read.csv') .pipe(parser) .pipe(your_writable_stream)
當心 : 此代碼立即返回。 它不等待操作完成。 它與node.js內部的隱藏事件循環進行交互。 事件循環經常使來自另一種語言的新開發人員感到困惑,他們習慣了命令式風格,而跳過了他們的node.js培訓這一部分。
實現這樣的定制可寫流可能會變得復雜,留給讀者練習。 如果解析器發出一行,這將是最簡單的,然后可以編寫編寫器來處理單行。 確保您能夠以某種方式注意到錯誤並拋出適當的異常,否則您將被不完整的結果所困擾,沒有警告或原因。
一種駭人聽聞的方法是將let parser = ...
console.log(data)
替換為自定義函數writeRowToSqlite(data)
,您必須編寫該函數才能實現自定義流。 由於異步API問題,使用return data
沒有任何用處。 如您所見,它肯定無法將數據放入輸出變量中。
output
不包含數據... 不幸的是,正如您發現的那樣,這通常是錯誤的:
const output = fs.createReadStream(__dirname + "/users.csv").pipe(parser); console.log(output);
在這里,變量output
將是ReadableStream ,它與可讀流中包含的數據不同。 簡而言之,就像文件系統中有文件一樣,您可以獲得有關文件的各種系統信息,但是文件中包含的內容是通過不同的調用來訪問的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.