node.js中fs.createReadStream vs fs.readFile的优缺点是什么?

我正在用node.js搞清楚,发现了两种读取文件的方法,一旦确定它存在并发送了正确的MIMEtypeswriteHead:

// read the entire file into memory and then spit it out fs.readFile(filename, function(err, data){ if (err) throw err; response.write(data, 'utf8'); response.end(); }); // read and pass the file as a stream of chunks fs.createReadStream(filename, { 'flags': 'r', 'encoding': 'binary', 'mode': 0666, 'bufferSize': 4 * 1024 }).addListener( "data", function(chunk) { response.write(chunk, 'binary'); }).addListener( "close",function() { response.end(); }); 

假设fs.createReadStream可以提供更好的用户体验,如果有问题的文件比较大,比如video,我是否正确? 感觉这可能不那么块; 这是真的? 还有其他的优点,缺点,警告或陷阱我需要知道吗?

一个更好的方法,如果你只是把“数据”连接到“写()”和“closures”到“end()”:

 // 0.3.x style fs.createReadStream(filename, { 'bufferSize': 4 * 1024 }).pipe(response) // 0.2.x style sys.pump(fs.createReadStream(filename, { 'bufferSize': 4 * 1024 }), response) 

read.pipe(write)sys.pump(read, write)方法的好处还在于增加stream量控制。 因此,如果写入stream不能快速接受数据,它会告诉读取stream回退,从而最大限度地减lesscaching在内存中的数据量。

flags:"r"mode:0666暗示它是一个FileReadStream。 不build议使用binary编码 – 如果未指定编码,则只能使用原始数据缓冲区。

此外,你可以添加一些其他的好东西,让你的文件服务很多闪烁:

  1. 嗅探req.headers.range并查看它是否匹配像/bytes=([0-9]+)-([0-9]+)/这样的string。 如果是这样,你只想从开始stream到结束位置。 (缺less数字表示0或“结束”。)
  2. 将stat()调用的inode和创build时间散列到ETag标头中。 如果你得到一个带有“if-none-match”匹配头的请求头,发回一个304 Not Modified
  3. 在stat对象上检查if-modified-since标题和mtimedate。 304自提供date起未经修改。

另外,一般来说,如果可以的话,发送一个Content-Length头。 (你正在归档文件,所以你应该有这个。)

fs.readFile会像指出的那样将整个文件加载到内存中,而fs.createReadStream将以您指定的大小读取文件。

客户端也将开始使用fs.createReadStream更快地接收数据,因为它正在被读取时以块的forms发送,而fs.readFile将读取整个文件,然后才开始将其发送到客户端。 这可能是微不足道的,但是如果文件非常大而且磁盘速度很慢,那么可以有所作为。

想想看,如果你在100MB的文件上运行这两个函数,第一个将使用100MB的内存来加载文件,而后者只能使用4KB。

编辑:我真的不明白为什么你会使用fs.readFile特别是因为你说你会打开大文件。

另一个也许不是那么广为人知的事情是,我相信Node比使用fs.readFile更好地清理使用fs.readFile之后的非使用内存。 你应该testing这个来validation什么效果最好。 此外,我知道每个新版本的Node都会变得更好(即垃圾收集器在这些types的情况下变得更聪明)。

如果它是一个大文件,那么“readFile”会占用内存,因为它会缓冲内存中的所有文件内容,并可能导致系统挂起。 ReadStream以块读取。

运行此代码并观察任务pipe理器的性能选项卡中的内存使用情况。

  var fs = require('fs'); const file = fs.createWriteStream('./big_file'); for(let i=0; i<= 1000000000; i++) { file.write('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n'); } file.end(); //.............. fs.readFile('./big_file', (err, data) => { if (err) throw err; console.log("done !!"); }); 

事实上,你不会看到“完成! 信息。 “readFile”将无法读取文件内容,因为缓冲区不足以容纳文件内容。

现在,而不是“readFile”,使用readStream和监视内存使用情况。

注意:代码取自Pluralsight的Samer buna Node课程