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

Javascript node.js中fs.createReadStream与fs.readFile的优缺点是什么?,javascript,file,node.js,fs,Javascript,File,Node.js,Fs,我正在研究node.js,发现了两种读取文件和发送文件的方法,一旦我确定文件存在并发送了正确的MIME类型和writeHead: // 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

我正在研究node.js,发现了两种读取文件和发送文件的方法,一旦我确定文件存在并发送了正确的MIME类型和writeHead:

// 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可能会提供更好的用户体验,这一假设正确吗?感觉它可能不那么像块;这是真的吗?我还需要知道其他的优点、缺点、注意事项或问题吗?

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

客户端还将使用
fs.createReadStream
更快地接收数据,因为在读取数据时数据会分块发送,而as
fs.readFile
将读取整个文件,然后才开始将其发送到客户端。这可能可以忽略不计,但如果文件很大且磁盘速度较慢,则可能会产生影响

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


编辑:我真的看不出你为什么要使用
fs.readFile
,尤其是因为你说你要打开大文件。

如果你只是想将“数据”连接到“写入()”并将“关闭”连接到“结束()”,这是一个更好的方法:

read.pipe(write)
sys.pump(read,write)
方法还可以增加流量控制。因此,如果写流不能尽快接受数据,它将告诉读流退出,以最小化内存中缓冲的数据量

标志:“r”
模式:0666
是一个
FileReadStream
。不推荐使用
二进制编码
编码——如果未指定编码,它将只处理原始数据缓冲区

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

  • 嗅探
    req.headers.range
    并查看它是否匹配
    /bytes=([0-9]+)-([0-9]+)/
    这样的字符串。如果是这样,您只需要从该起始位置流到结束位置。(缺失的数字表示0或“结束”。)
  • 将stat()调用中的inode和创建时间散列到ETag头中。如果您得到一个与该头匹配的“If none match”请求头,则返回一个
    304 Not Modified
  • 对照统计对象上的
    mtime
    日期,检查
    (如果自
    修改)标题。304如果自提供的日期起未进行修改

  • 此外,通常,如果可以,请发送
    内容长度
    标题。(您正在统计文件,所以您应该有这个。)

    另一件可能不太为人所知的事情是,我相信在使用
    fs.readFile
    之后,与
    fs.createReadStream
    相比,Node在清理未使用的内存方面更出色。您应该对此进行测试,以验证什么最有效。此外,我知道,每一个新版本的Node都会让这一点变得更好(即垃圾收集器在这种情况下变得更智能)。

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

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

     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 !!");
    });
    
    var fs=require('fs');
    const file=fs.createWriteStream('./big_file');
    for(设i=0;i{
    如果(错误)抛出错误;
    log(“完成!!”);
    });
    
    事实上,您不会看到“完成!!”消息。 “readFile”无法读取文件内容,因为缓冲区不够大,无法容纳文件内容

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


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

    @isaacs,请您提供一个如何实施这3个步骤的示例,谢谢!
    bufferSize
    选项已被弃用,取而代之的是
    highWaterMark
    。这甚至是如何回答最初提出的问题的?这意味着使用
    fs.readFile
    我们无法捕捉每个示例的进度?
     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 !!");
    });