文件读取和流式处理有什么区别?

what is difference between file reading and streaming?

提问人:OMar Mohamed 提问时间:7/19/2016 最后编辑:OMar Mohamed 更新时间:5/11/2021 访问量:8570

问:

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

JavaScript node.js Web 服务器端

评论

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

答:

10赞 Patrick Roberts 7/19/2016 #1

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

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

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

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

这里有两个片段展示了我所说的内容:

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
});
22赞 Devendra Verma 7/19/2016 #2

首先是fileread是完全缓冲的方法。而流式处理是部分缓冲方法。

现在这是什么意思?

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

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

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

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

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

评论

1赞 Patrick Roberts 7/19/2016
由于 readFile 和 readFileSync 都返回包含所有数据的字符串 - 错误,因此除非显式指定编码,否则它们默认返回对象。Buffer