Node.js Stream API出现意外行为

时间:2016-02-28 01:00:43

标签: node.js parsing csv filestream piping

我尝试通过解析器管道CSV文件,删除给定ID的行,将新数组传输到字符串,然后最终将结果输出到新的CSV。

问题是新数组未正确返回。我的意思是,我设法删除该行但不返回新的CSV。

以下是CSV file

以下是代码:

'use strict';


const Fs    = require('fs');
const Csv   = require('csv');


let input  = 'data_stack.csv';
let output = 'data_output.csv';


let readStream  = Fs.createReadStream(input);
let writeStream = Fs.createWriteStream(output);

let opt  = {delimiter: ',', quote: '"', escape: '"', relax: true, skip_empty_lines: true};

function deleteRow (id) {

    return Csv.parse(opt, (err, data) => {
        if (err) throw err;

        let delId = [];
        // The row corresponding to the id is pushed to an array to console.log it. The other rows are returned 
        let newData = data.filter(line => {
            if (line[0] === id) {
                delId.push(line);
            }
            else {
                return line;
            }
        });

        if (delId !== 0) {
            console.log("Deleted line\n");
            console.log(delId);
        }

        // Testing if the row was deleted
        let result = [];
        // If the row is not deleted, push it into the result array
        newData.forEach(line => {
            if (line[0] === id) {
                result.push(line);
            }
        });
        // "Not found !" is console logged. The row has been deleted 
        if (result.length !== 0) {
            console.log(result);
        }
        else {
            console.log("Not found !");
        }

        return newData;
    });
}

readStream.pipe(deleteRow('566150121ae803f53751c3f2'))

此代码正常运行 但是如果我选择返回newData数组来管道一个字符串,然后将结果输出到CSV文件,我会得到2个意外的行为:

  1. delId数组现在为空,我不知道为什么
  2. 创建了输出文件,但之前删除的行仍然存在于输出文件
  3. 以下是代码:

    'use strict';
    
    
    const Fs    = require('fs');
    const Csv   = require('csv');
    
    
    let input  = 'data_stack.csv';
    let output = 'data_output.csv';
    
    
    let readStream  = Fs.createReadStream(input);
    let writeStream = Fs.createWriteStream(output);
    
    let opt  = {delimiter: ',', quote: '"', escape: '"', relax: true, skip_empty_lines: true};
    
    function deleteRow (id) {
    
        return Csv.parse(opt, (err, data) => {
            if (err) throw err;
    
            let delId = [];
            // The row corresponding to the id is pushed to an array to console.log it. The other rows are returned 
            let newData = data.filter(line => {
                if (line[0] === id) {
                    delId.push(line);
                }
                else {
                    return line;
                }
            });
    
            if (delId !== 0) {
                console.log("Deleted line\n");
                console.log(delId);
            }
    
            // Testing if the row was deleted
            let result = [];
            // If the row is not deleted, push it into the result array
            newData.forEach(line => {
                if (line[0] === id) {
                    result.push(line);
                }
            });
            // "Not found !" is console logged. The row has been deleted 
            if (result.length !== 0) {
                console.log(result);
            }
            else {
                console.log("Not found !");
            }
    
            return newData;
        });
    }
    
    let stringifier = Csv.stringify({quoted: true});
    
    readStream.pipe(deleteRow('566150121ae803f53751c3f2')).pipe(stringifier).pipe(writeStream);
    

    我真的不明白来自deleteRow函数的结果如何影响它的行为。

    有任何建议吗?

1 个答案:

答案 0 :(得分:0)

csv.parse2 APIs

  1. 基于回调(缓冲)和;
  2. Streams based。
  3. 如果您传递回调函数,就像您在示例中所做的那样,您正在订阅回调API,这意味着您可以通过data参数获得整个解析后的数据。

    但是,该回调是一个流'sink',这意味着对数据的任何修改都不会归结为writeStream

    您需要调整代码以使用回调API,如下所示:

    function deleteRow(readStream, id, done) {
      readStream.pipe(Csv.parse(opt, (err, data) => {
        if (err) return done(err);
    
        // Wrire new data to file
        Csv.stringify(data.filter(line => line[0] !== id))
          .pipe(writeStream)
          .on('end', done);
      }));
    }
    
    deleteRow(readStream, '5660d7e11ae803f53751aeb0', function (err) {
      console.log('done!');
    });
    

    或者,使用像这样的流API: