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

有帮助吗?

解决方案

一个更好的方法,如果您只想将“数据”连接到“ 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 对编码进行了弃用 - 如果未指定编码,它将仅与原始数据缓冲区一起使用。

另外,您可以添加其他一些好东西,使您的文件提供非常光滑:

  1. 嗅探 req.headers.range 看看它是否与像字符串一样 /bytes=([0-9]+)-([0-9]+)/. 。如果是这样,您只想从该开始到结束位置流式传输。 (缺少数字表示0或“末端”。)
  2. 哈希(Hash)从stat()呼叫到ETAG标头的Inode和创建时间。如果您获得了带有“如果不匹配”匹配该标题的请求标题,请发送回一个 304 Not Modified.
  3. 检查 if-modified-since 标题对阵 mtime 统计对象上的日期。 304如果未经修改,则自提供的日期以来。

另外,通常,如果可以的话,请发送 Content-Length 标题。 (你是 stat- 对文件,所以您应该有这个。)

其他提示

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

客户还将开始使用 fs.createReadStream 当它被读取时,它被读取时, fs.readFile 将读取整个文件,然后才开始将其发送给客户端。这可能可以忽略不计,但是如果文件很大并且磁盘慢,则可以有所作为。

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

编辑:我真的看不到您使用的任何理由 fs.readFile 特别是因为您说您将打开大型文件。

如果它是一个大文件,那么“ 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 !!");
});

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

现在使用ReadStream并监视内存使用量,而不是“ ReadFile”。

注意:代码是从pluralsight上的Samer Buna节点课程中获取的

另一个也许不是那么知名的事情是,我相信节点在使用后最好清理未使用的内存 fs.readFile 相比 fs.createReadStream. 。您应该对此进行测试以验证哪些方法最有效。另外,我知道,通过每一个新版本的节点,情况都变得更好(即垃圾收集器对这些类型的情况变得更加聪明)。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top