如何异步写入和读取节点中的同一文件?

时间:2017-03-07 18:06:41

标签: javascript node.js

我通过websocket传入数据。它以20ms的块发送二进制数据。我需要连接这些块中的每一个,以便后端进程可以在连续流中读取数据。

//Create the file and append binary as it comes in

    tmp.file({postfix: '.raw' },function (err, path, fd, cleanup) {
    if (err) throw err;
    newPath = path
        fs.appendFile(newPath, new Buffer(binary), (err) => {
            if (err) throw err;

        })
    })

//Read the file as it is written
    fs.createReadStream(newPath).pipe(recStream);

现在我只在createReadStream上有一个简单的半秒延迟,以确保文件中有数据。

这当然感觉不正确并且无法正常工作。什么是正确的方法?

1 个答案:

答案 0 :(得分:2)

在这种情况下,最好的办法是告诉服务器您接收数据暂停,直到您准备好处理更多(drain)。假设不适合你:

首先将传入数据写入目标流。如果write(chunk)返回false,则表示流的内部缓冲区已满;是时候开始将后续数据缓冲到磁盘了。 (您刚写入的chunk导致false返回值缓冲;不要将其写入磁盘 - false并不意味着写入失败,它只是一个信号,表明缓冲区的数据多于highWaterMark。)

在临时文件夹中,创建一个新文件( A )写入流,并将下一个传入数据块写入其中。这样做直到您的目标流发出drain事件。

目的地drain时:

  1. 交换缓冲区文件。关闭当前缓冲区文件 A 并创建一个新的临时文件 B 以开始向其写入新的传入数据。
  2. 在临时文件 A 上打开读取流,并开始将数据从中传输到目标流中。您可能无法使用实际的pipe()方法,因为它会在您到达临时文件的末尾时发出数据结束信号,这不是我们想要的,因为它不是所有的实际结束传入的数据。 (Look at what pipe() does并自行实施,减去调用end()。)
  3. 当临时文件的流 A 发出end时,请删除文件 A 。然后返回步骤1并使用文件 B 再次开始该过程。 (如果在此期间没有数据写入文件 B ,请返回无缓冲操作,将传入数据直接写入目标流。)
  4. 一旦服务器发出信号表示已完成发送数据,所有数据都已从您的临时文件中write(null)读入目标流,以表示没有更多数据。一切都完成了!

    通过在临时缓冲区文件之间交换并在处理完数据后删除它们,您不必担心在将数据写入文件时读取数据。另外,您不必将整个传入数据流缓冲在磁盘上。

    当然,这确实假设您的存储介质可以保证比通过网络接收数据更快地接受写入。这可能是安全的,但如果这个假设不正确,事情可能会崩溃。使用生产系统测试 - 什么是峰值传入数据速率以及您在prod系统上写入磁盘的速度有多快?