我正在讨论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可能提供更好的用户体验,如果有问题的文件是大的,如视频?感觉它可能不那么块状;这是真的?还有其他我需要知道的优点,缺点,警告或陷阱吗?
答案 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
隐含在FileReadStream
和binary
之间。不推荐使用req.headers.range
编码 - 如果未指定编码,则只使用原始数据缓冲区。
此外,您可以添加一些其他好东西,使您的文件服务更加流畅:
/bytes=([0-9]+)-([0-9]+)/
并查看它是否与304 Not Modified
之类的字符串匹配。如果是这样,您只想从该开始到结束位置进行流式传输。 (缺少数字表示0或“结束”。)if-modified-since
。mtime
日期的Content-Length
标题。如果自提供日期以来未进行修改,则为304。此外,通常情况下,如果可以,请发送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.readFile
与fs.createReadStream
相比后,Node更善于清理未使用的内存。您应该对此进行测试以验证最佳效果。此外,我知道每个新版本的Node都会变得更好(即垃圾收集器在这些情况下变得更聪明)。