[英]NodeJS CSVReader - createReadStream with csv-parse returns empty array
我有 CSV 阅读器 class,它采用两个参数(文件路径和模型)。 文件路径为.csv文件的路径,model为model,即.Z628CB5675FF5288B3AF775FF528F3AFE7 数据将存储在 output 阵列中。 它有一个问题,因为当我返回数组时,它是空的。 但是当我控制台记录数组时,它里面有数据。 有人能帮我吗?
索引.js
const parse = require('csv-parse')
const fs = require('fs');
const output = [];
class CSVReader{
static GetRecord(filePath, model){
fs.createReadStream(filePath)
.pipe(parse({columns: false, delimiter: ',', trim: true, skip_empty_lines: true}))
.on('readable', function (){
let record
while (record = this.read()){
let city = model.create(record)
output.push(record)
}
})
.on('end', function (){
//console.log(output);
})
return output;
}
}
module.exports = CSVReader;
我用 Jest 测试了文件,但它有一个问题,正如预期的那样是 6,但我收到了 []
索引.test.js
const CSVReader = require('../src/Index');
const City = require('../src/Models/City')
test('Can Read CSV File', () => {
let filePath = 'data/worldcities.csv';
let records = CSVReader.GetRecord(filePath, City);
expect(records.length).toBe(6);
});
这是一个异步调用,因此您不能只返回响应并期望它起作用。 您需要使用 Promise API 和异步 function。
所有 Node.js fs
API 都是异步的(不包括fs.*Sync
功能)。
您可以在Promise
的顶部返回 Promise,然后传递回调:
return new Promise((resolve, reject) => { /* callback */ });
// all of this is fine
const parse = require('csv-parse')
const fs = require('fs');
// remove the const output = []; as this will cause problems
class CSVReader{
// this needs to be async
static async GetRecord(filePath, model){
// return a promise
return new Promise((resolve, reject) => {
// assign output here (https://stackoverflow.com/a/66402114/14133230)
const output = [];
fs.createReadStream(filePath)
.pipe(parse({columns: false, delimiter: ',', trim: true, skip_empty_lines: true}))
.on('readable', function (){
let record
while (record = this.read()){
let city = model.create(record)
output.push(record)
}
// you may need to call WriteStream#close() here
})
.on('end', function (){
// output is available here
// resolve the promise
resolve(output);
})
});
}
}
module.exports = CSVReader;
const CSVReader = require('../src/Index');
const City = require('../src/Models/City')
test('Can Read CSV File', () => {
let filePath = 'data/worldcities.csv';
let records = CSVReader.GetRecord(filePath, City); // type Promise
records.then((response) => { // when promise fills
expect(response.length).toBe(6);
});
});
第一个建议:删除库 class 中全局定义的“const output = []”。 这会给使用您的 static 方法的人造成很大的困惑。 您最终会在那里累积以前调用的结果。
我还建议:如果您不需要它来处理巨大的 csv 文件,那么您绝对可以将 go 用于同步版本,并摆脱异步加载的复杂性。
const parse = require('csv-parse/lib/sync');
const fs = require('fs');
class CSVReader{
static GetRecord(filePath, model) {
const csvContents = fs.readFileSync(filePath);
const output = parse(csvContents, {columns: false, delimiter: ',', trim: true, skip_empty_lines: true})
.map(function (record) {
return model.create(record);
});
return output;
}
}
module.exports = CSVReader;
另一个可能有用的重组可能来自将工厂模式(您目前打算使用 CSVReader 实现)直接附加到模型的基本实现。 这将更清楚哪些模型可与 CSVReader 一起使用,以及 Model 的实现如何构造为可用于该模式。
基础CSVModel
提供通用listFromCSV
功能和modelFromRecord
实例化。
src/Models/CSVModel.js
const parse = require('csv-parse/lib/sync');
const fs = require('fs');
class CSVModel {
static modelFromRecord(record) {
var model = new this();
model.record = record;
return model;
}
static listFromCSV (filePath) {
const csvContents = fs.readFileSync(filePath);
return parse(csvContents, {columns: false, delimiter: ',', trim: true, skip_empty_lines: true})
.map((record) => {
return this.modelFromRecord(record);
});
}
}
module.exports = CSVModel;
City
model 从 CSVModel 继承listFromCSV
工厂,并指定其与本地 model 属性的数据关联
src/Models/City.js
const CSVModel = require('./CSVModel');
class City extends CSVModel {
static modelFromRecord(record) {
var model = super.modelFromRecord(record);
// assign properties of the CSV row to dedicated model properties
[model.name, model.id, model.asd] = [record[0], record[1], record[2]];
// or classical
model.name = record[0];
// ...
return model;
}
}
module.exports = City;
这允许使用具体的 Model Class 从 CSV 实例化列表。
test/csvmodel.test.js
const City = require('../src/Models/City');
test('Can Read City list', () => {
let filePath = 'data/worldcities.csv';
let records = City.listFromCSV(filePath);
expect(records.length).toBe(6);
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.