【问题标题】:what is difference between file reading and streaming?文件读取和流式传输有什么区别?
【发布时间】:2016-11-22 09:30:11
【问题描述】:

我在某本书中读到使用流式传输比在 node.js 中一次读取整个文件更好,我理解这个想法.. 但我想知道不是使用流式读取文件吗?我已经习惯了 Java 和 C++ 的这一点,当我想读取文件时,我使用流 .. 那么这里有什么区别呢? 还有fs.createReadStream(<somefile>);fs.readFile(<somefile>);之间的区别是什么? 两者都是异步的,对吧!!

【问题讨论】:

  • 我相信不同之处在于“读取整个文件”将整个文件放入内存中,而“流式处理”则以块的形式处理文件。
  • 而流需要异步控制流,因为您不知道下一个块何时交付。
  • 所以,唯一的区别是“流节省内存”,因为流和 fs.readFile 方法都是异步(非阻塞)@FrédéricHamidi
  • @Omar,我不认为异步方面比能够在不投资 42 TB RAM 的情况下处理 42 TB 文件更重要。

标签: javascript node.js web server-side


【解决方案1】:

首先是 fileread 是完全缓冲的方法。并且流是部分缓冲的方法。

现在是什么意思?

完全缓冲的函数调用,如 readFileSync() 和 readFile() 暴露 数据作为一个大块。也就是说,执行读取,然后以同步或异步方式返回完整的数据集。 使用这些完全缓冲的方法,我们必须等到所有数据都被读取,并且 Node 内部需要分配足够的内存来将所有数据存储在内存中。这可能是有问题的 - 想象一个从磁盘读取 1 GB 文件的应用程序。只有完全缓冲的访问,我们需要使用 1 GB 的内存来存储文件的全部内容以供读取 - 因为 readFile 和 readFileSync 都返回一个包含所有数据的字符串。

部分缓冲的访问方法不同。它们不将数据输入视为离散事件,而是将其视为在读取或写入数据时发生的一系列事件。它们允许我们在从磁盘/网络/其他 I/O 读取数据时访问数据。

流返回数据的较小部分(使用缓冲区),并在新数据可用于处理时触发回调。

流是 EventEmitter。例如,如果我们的 1 GB 文件需要以某种方式处理一次,我们可以使用流并在读取数据后立即处理数据。这很有用,因为我们不需要将内存中的所有数据保存在某个缓冲区中:处理后,我们不再需要为此类应用程序将数据保存在内存中。

Node 流接口由两部分组成:可读流和可写流。有些流既可读又可写。

【讨论】:

  • 因为 readFile 和 readFileSync 都返回包含所有数据的字符串 - 错误,除非您明确指定编码,否则它们默认返回 Buffer 对象。
【解决方案2】:

那么这里有什么不同??还有fs.createReadStream(<somefile>);fs.readFile(<somefile>);的区别是什么都是异步的,对吧!!

除了fs.createReadStream() 直接返回stream 对象,fs.readFile() 在第二个参数中期望回调函数之外,还有另一个巨大的区别。

是的,它们都是异步的,但这并不会改变fs.readFile() 在整个文件被缓冲到内存之前不会给你任何数据的事实。当通过服务器响应中继数据时,这会大大降低内存效率并且速度较慢。使用fs.createReadStream(),您可以将pipe() stream 对象直接指向服务器的response 对象,这意味着即使文件为500MB,您的客户端也可以立即开始接收数据。

不仅如此,您还可以通过一次处理一个文件块而不是一次处理所有文件来提高内存效率。这意味着您的内存只需一次缓冲几 KB 的 file 内容,而不是一次全部缓冲。

这里有两个 sn-ps 演示了我的意思:

const fs = require('fs');
const http = require('http');

// using readFile()
http.createServer(function (req, res) {
    // let's pretend this is a huge 500MB zip file
    fs.readFile('some/file/path.zip', function (err, data) {
        // entire file must be buffered in memory to data, which could be very slow
        // entire chunk is sent at once, no streaming here
        res.write(data);
        res.end();
    });
});

// using createReadStream()
http.createServer(function (req, res) {
    // processes the large file in chunks
    // sending them to client as soon as they're ready
    fs.createReadStream('some/file/path.zip').pipe(res);
    // this is more memory-efficient and responsive
});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-03-21
    • 1970-01-01
    • 2014-01-23
    • 2015-11-18
    • 1970-01-01
    • 1970-01-01
    • 2012-12-17
    相关资源
    最近更新 更多