使用 Bluebird 将所有 csv 文件读入节点 js 中的 1 个 JSON 对象数组

Posted

技术标签:

【中文标题】使用 Bluebird 将所有 csv 文件读入节点 js 中的 1 个 JSON 对象数组【英文标题】:read all csv files into 1 JSON object array in node js with Bluebird 【发布时间】:2016-10-18 15:11:59 【问题描述】:

我是在 nodeJS 中使用 Promise Bluebird 的新手。

我想将特定目录中的所有 CSV 文件读入 1 个 JSON 对象数组并显示结果。

步骤如下:

    读取目录获取文件名(调用函数readDir) 使用循环读取每个 CSV 文件(lodash forOwn 循环)并将内容存储在 JSON 对象数组中(调用函数 ReadFile) 将 JSON 对象数组(使用 Lodash 分配函数)与主要 JSON 对象数组(名为 data_Warehouse)合并,以便将所有数据存储到 1 个 JSON 对象数组中。 将所有 CSV 文件数据保存到 JSON 对象数组 data_Warehouse 后,在 console.log(.then 部分)中显示 data_Warehouse。

检查是否一切按计划进行,我在代码之间放入了console.log。 问题是这些过程没有按正确的顺序完成。我尝试使用 Bluebird,但它仍然没有按计划进行。

您能帮我解决这个问题吗?

这是我的输出:


输出:加载\Book1.csv

输出:加载\Book2.csv

输出:加载\Book3.csv

结果:

加载\Book1.csv 101

加载\Book2.csv 102

加载\Books.csv 103


如您所见,行输出“结果”应该是最后一行,但它在 JSON 对象数组 data_Warehouse 为空的过程中较早。

var Converter = require("csvtojson").Converter;
var converter = new Converter();
var _ = require('lodash');
var r = require('rethinkdbdash')(config.rethinkdb);
var fs = Promise.promisifyAll(require('fs'));

readDir()
  .then(function(v)

      var data_Warehouse=;
      _.forOwn(v, function(index)
        console.log('output:' + index);
        _.assign(data_Warehouse, readFile(index));
      );
      return mine;

  ).then(function(w)
      console.log('Results:' + w.length);
  )

function readDir() 
    return fs.readdirAsync(dir).map(function (fileName) 
        var path = Path.join(dir, fileName);
        return fs.statAsync(path).then(function(stat) 
            return stat.isDirectory() ? readDir(path) : path;
        );
    ).reduce(function (a, b) 

        return a.concat(b);
    , []);



function readFile(fileName)
  var converter = new Converter();
    fs.createReadStream(fileName).pipe(converter);
    converter.on("end_parsed", function (jsonArray) 
      console.log(fileName + ' ' + jsonArray[0].Order_ID);
      return jsonArray;
    )


我更改了我的代码(使用了 promisifyAll),现在能够读取指定目录中的所有文件并以正确的顺序显示结果,但是现在使用 csvtojson 将读取的数据转换为每个文件上的 json问题。它会在 console.log('results: ' + result[Ticker].Order_ID); 之前显示'done....' (见下面的输出)。

var join = Promise.join;
var fs = Promise.promisifyAll(require("fs"));
var Converter = require("csvtojson").Converter;
var Promise = require('bluebird');
var dir='./load/';

fs.readdirAsync(dir).map(function(fileName) 
  var contents = fs.readFileAsync(fileName).catch(function ignore() );
  return join(fileName, contents, function(fileName, contents) 
      return 
        fileName: fileName,
        contents: contents
      
  );

).each(function(file) 
    console.log('File Name: ' + file.fileName + '\n');
    console.log('output: ' + file.contents + '\n');

    var converter = new Converter();
    var temp = file.contents.toString();
    var tmp;
    converter.on("end_parsed", function() );
    converter.fromString(temp, function(err, result)
      tmp = result;
      for(var Ticker in result)
        console.log('results: ' + result[Ticker].Order_ID);
      
    );

    console.log('___________________');
    return tmp;
).then(function(contents) 
    console.log('Done.............');
)

我现在的输出是:

文件名:Book1.csv

输出:Order_ID、数量、价格、日期、备注

123、1000、12.95、10/8/2015、测试 786、100、7.95、11/6/2015、test2


文件名:Book2.csv

输出:Order_ID、数量、价格、日期、备注

4526、800、2.95、4/1/2015、test3 129、10、3.66、1/23/2014、test4


完成......

结果:1​​23

结果:786

结果:4526

结果:1​​29

如何以正确的顺序将转换器 csvtojson 带回,以便“完成...”在流程结束时结束?

已编辑:

现在我已经承诺 csvtojson 但由于某种原因它不起作用。

var join = Promise.join;
var fs = Promise.promisifyAll(require("fs"));
var Converter = require("csvtojson").Converter;
var Promise = require('bluebird');
var dir='./load/';

  jsons= function(data)
  var converter = new Converter();
  var output;
  converter.on("end_parsed", function() );
  converter.fromString(data, function(err, result)
    for(var Ticker in result)
      console.log('results: ' + result[Ticker].Ticker);
    
    output = result;
  );
return output;
;

var conversionJsons = Promise.promisifyAll(jsons);

fs.readdirAsync(dir).map(function(fileName) 
  var contents = fs.readFileAsync(fileName).catch(function ignore() );
  return join(fileName, contents, function(fileName, contents) 
      return 
        fileName: fileName,
        contents: contents
      
  );


).each(function(file) 
    console.log('File Name: ' + file.fileName + '\n');
    console.log('output: ' + file.contents + '\n');

    console.log('___________________');
    var temp = file.contents.toString();
    conversionJsons(temp).then(function(result)     //  <----Error here for then
console.log("results are: "+ result);
return result;

    );
).then(function(contents) 
    console.log('Done.............');

)

我收到以下错误:

“无法读取未定义的属性'then'”

您能帮我解决这个问题吗?

【问题讨论】:

【参考方案1】:

好吧,您正在遭受race condition 的困扰,因为您的操作是异步运行的。

我的建议是按照你想要的顺序使用一系列承诺和chain them,然后等到所有内容都完成后再发送你想要的结果,你应该使用promise.all

【讨论】:

我现在更改了我的代码。所有文件都在开始时读取。转换 csvtojson 是我现在的问题。 尝试将所有的promise包装成一个数组,然后使用promise.all 我改变了我的代码来包装承诺,但我可以错误“无法读取未定义的属性'then'”

以上是关于使用 Bluebird 将所有 csv 文件读入节点 js 中的 1 个 JSON 对象数组的主要内容,如果未能解决你的问题,请参考以下文章

将当前工作目录中的所有 CSV 文件读入具有正确文件名的 pandas

使用 CsvHelper 将 CSV 中的所有值读入列表

将特定行的csv读入php

将包含一些空值的CSV文件读入VBA数组

将文件夹中的多个csv文件读入R中的单个数据框[重复]

使用分块将 CSV 文件读入 Pandas 数据帧,生成单个目标数据帧