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

时间:2011-01-04 00:46:43

标签: javascript file node.js fs

我正在讨论node.js并且已经发现了两种读取文件并将其发送到网络的方法,一旦我确定它存在并且已经使用writeHead发送了正确的MIME类型:

// 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可能提供更好的用户体验,如果有问题的文件是大的,如视频?感觉它可能不那么块状;这是真的?还有其他我需要知道的优点,缺点,警告或陷阱吗?

4 个答案:

答案 0 :(得分:56)

更好的方法,如果您只是将“数据”连接到“write()”并“关闭”到“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)方法的好处是还可以添加流量控制。因此,如果写入流不能快速接受数据,它将告诉读取流退出,以便最小化在内存中缓冲的数据量。

flags:"r"mode:0666隐含在FileReadStreambinary之间。不推荐使用req.headers.range编码 - 如果未指定编码,则只使用原始数据缓冲区。

此外,您可以添加一些其他好东西,使您的文件服务更加流畅:

  1. 嗅探/bytes=([0-9]+)-([0-9]+)/并查看它是否与304 Not Modified之类的字符串匹配。如果是这样,您只想从该开始到结束位置进行流式传输。 (缺少数字表示0或“结束”。)
  2. 将stat()调用中的inode和创建时间散列到ETag标头中。如果您收到与该标头匹配的“if-none-match”请求标头,请发送回if-modified-since
  3. 检查统计对象上mtime日期的Content-Length标题。如果自提供日期以来未进行修改,则为304。
  4. 此外,通常情况下,如果可以,请发送stat标头。 (你是{{​​1}} - 文件,所以你应该有这个。)

答案 1 :(得分:37)

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

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

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

编辑:我真的没有看到你使用fs.readFile的原因,特别是因为你说你将要打开大文件。

答案 2 :(得分:2)

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

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

library(dplyr)

df %>% 
 group_by(Id) %>% 
 mutate(new = replace(lag(duration.minutes), event != 'stop', NA))

#Source: local data frame [10 x 4]
#Groups: Id [2]

#      Id duration.minutes  event   new
#   <chr>            <int> <fctr> <int>
#1      a               NA  enter    NA
#2      b              139   trip    NA
#3      b              535   stop   139
#4      b              150   trip    NA
#5      a               NA   exit    NA
#6      a               NA  enter    NA
#7      b              145   trip    NA
#8      b              545   stop   145
#9      a              144   trip    NA
#10     a               NA   exit    NA

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

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

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

答案 3 :(得分:0)

另一个,也许不是那么知名的事情,是我认为在使用fs.readFilefs.createReadStream相比后,Node更善于清理未使用的内存。您应该对此进行测试以验证最佳效果。此外,我知道每个新版本的Node都会变得更好(即垃圾收集器在这些情况下变得更聪明)。