如何等待 stream.write() 循环结束

Posted

技术标签:

【中文标题】如何等待 stream.write() 循环结束【英文标题】:How to wait for loop of stream.write() to end 【发布时间】:2021-03-02 09:55:03 【问题描述】:

我正在使用 Node 的 fs.WriteStream 将数据写入文件。我正在遍历一个对象数组并使用 write() 函数写入每个对象。

问题是我想知道一旦这个循环结束并且所有 write() 调用都完成了,但我无法让它工作。

我尝试了一些解决方案,例如不使用流,但这会产生其他问题。我上次尝试的解决方案是检查循环是否是最后一项,如果是,则关闭、结束或销毁流。

这些都不起作用。该事件是在文件实际写入之前发出的。

下面是我的代码,我很感激我能得到任何帮助。非常感谢。

    async function writeFile(path, data) 

    try 

        const writeStream = fs.createWriteStream(path, 
            flags: "w"
        )

        data.forEach((file, index) => 
            writeStream.write(`$file.name\n`, (err) => 
                if(err) throw err
                if(index === (data.length - 1)) writeStream.end(); //I attempted close() and destroy() too, none worked
            )
        )

        writeStream.on("finish", () => 
            console.log("All files were written.") //Currently being emmited before all is written.
        )

     catch (err) 

        throw (err)
    

【问题讨论】:

也许这有帮助? ***.com/questions/2641347/…?否则使用 for 循环 【参考方案1】:

由于您的文件数据已经在内存中,因此看起来并没有那么大,我只需将其转换到内存中并在一次调用 fs.writeFile()fs.promises.writeFile() 时将其写出来。

function writeFile(path, data) 
    let fileData = data.map(file => file.name + "\n").join("");
    return fs.promises.writeFile(path, fileData);


如果您真的想使用流,那么您必须非常小心地注意.write() 返回的内容,以防写入缓冲区已满,以便您可以等待排水事件。

const fs = require('fs');

function writeFile(path, data, completionCallback) 
    let index = 0;
    const writeStream = fs.createWriteStream(path,  flags: "w" );

    writeStream.on('error', function(err) 
        // stream will be automatically closed here
        completionCallback(err);
    );

    // write one piece of data and call callback
    // when ready to write the next piece of data
    function writeData(data, cb) 
        if (!writeStream.write(data)) 
            // when .write() returns false, you have to wait for the drain
            // event before doing any more writing
            stream.once('drain', cb);
         else 
            // so we always call the callback asynchronously and have no
            // stack buildup
            process.nextTick(cb);
        
    

    function run() 
        if (index < data.length) 
            let line = data[index++].name + "\n";
            writeData(line, run);
         else 
            // all done with no errors
            writeStream.end(completionCallback);
        
    

    run();

【讨论】:

@pedrodalla - 这回答了你的问题吗?如果是这样,您可以通过单击答案左侧的复选标记向社区表明这一点,这也将为您在此处获得一些声誉积分,以遵循正确的程序。【参考方案2】:

你可以试试这个方法吗,

const util = require("util");

async function writeFile(path, data) 
    try 
        const writeStream = fs.createWriteStream(path, 
            flags: "w"
        );

        const promisify = util.promisify(writeStream.write);

        for (const file of data) 
            await promisify(`$file.name\n`);
        
        
        writeStream.end();
        writeStream.on("finish", () => 
            console.log("All files were written.");
        );

     catch (error) 
        console.log('error',error);
        throw (error)'
    

【讨论】:

这是什么:const promisify = util.promisify(writeStream);writeStream 是一个有方法的对象,而不是一个函数。你不需要传递promisify()一个函数吗? 还有几个问题。 stream.write() 返回一个布尔值,告诉您流缓冲区是否已满,您必须等待耗尽事件,然后再写入更多内容。这并不能说明这一点。此外,流错误不会通过.write() 回调可靠地出现 - 它们来自错误事件。 Streams 几乎是一团糟,因为它们的事件驱动系统不能很好地与 Promise 保持一致。

以上是关于如何等待 stream.write() 循环结束的主要内容,如果未能解决你的问题,请参考以下文章

Javascript:在循环继续之前等待函数结束[重复]

windows API主线程如何等待子线程结束后再继续运行

等待 process.nextTick 循环结束

如何结束 while True: 打印所有可能性后循环?

java 异步查询转同步多种实现方式:循环等待,CountDownLatch,Spring Even

怎么让当前线程等待另一个线程完成之后再去执行