为什么Node.js在完成非流动的流副本之前退出

时间:2014-08-07 04:57:17

标签: node.js

我正在学习node.js,并希望编写一个简单的测试程序,将文件从源文件夹复制到目标文件夹。我将fs.ReadStream传送到fs.WriteStream,并且完美无缺。我接下来尝试使用非流动模式,但是下面的程序在较大的文件(超过1MB)上99%的时间都会失败。我假设在给定特定时间的情况下事件队列变空并因此退出。以下程序应该有效吗?

var sourcePath = "./source/test.txt";
var destinationPath = "./destination/test.txt";

// Display number of times 'readable' callback fired
var callbackCount = 0;
process.on('exit', function() {
    console.log('Readable callback fired %d times', callbackCount);
})

var fs = require('fs');
var sourceStream = fs.createReadStream(sourcePath);
var destinationStream = fs.createWriteStream(destinationPath);

copyStream(sourceStream, destinationStream);

function copyStream(src, dst) {
    var drained = true;

    // read chunk of data when ready
    src.on('readable', function () {
        ++callbackCount;
        if (!drained) {
            dst.once('drain', function () {
                writeToDestination();
            });
        } else {
            writeToDestination();
        }

        function writeToDestination() {
            var chunk = src.read();

            if (chunk !== null) {
                drained = dst.write(chunk);
            }
        }
    });

    src.on('end', function () {
        dst.end();
    });
}

注意:如果我删除了与排水相关的代码,程序总是有效,但node.js文档表明如果write函数返回false,你应该等待排水事件。

上述程序应该按原样运行吗?如果不应该如何重新组织它以同时处理readabledrain事件?

1 个答案:

答案 0 :(得分:0)

看起来你大部分都在那里;你需要改变一些事情。

  1. 写信至dst时,您需要继续阅读src,直至获得null chunkdst.write()返回false
  2. 而不是监听readable上的所有src事件,只有在可以写入dst并且您目前无需编写任何内容时,您应该只监听这些事件。
  3. 这样的事情:

    function copyStream(src, dst) {
        function writeToDestination() {
            var chunk = src.read(),
                drained = true;
    
            // write until dst is saturated or there's no more data available in src
            while (drained && (chunk !== null)) {
                if (drained = dst.write(chunk)) {
                    chunk = src.read();
                }
            }
    
            if (!drained) {
                // if dst is saturated, wait for it to drain and then write again
                dst.once('drain', function() {
                    writeToDestination();
                });
            } else {
                // if we ran out of data in src, wait for more and then write again
                src.once('readable', function() {
                    ++callbackCount;
                    writeToDestination();
                });
            }
        }
    
        // trigger the initial write when data is available in src
        src.once('readable', function() {
            ++callbackCount;
            writeToDestination();
        });
    
        src.on('end', function () {
            dst.end();
        });
    }