首页 > 语言 > JavaScript > 正文

Node.js从字符串生成文件流的实现方法

2024-05-06 15:35:47
字体:
来源:转载
供稿:网友

一.背景

在文件相关的数据加工等场景下,经常面临生成的物理文件应该如何处理的问题,比如:

生成的文件放到哪里,路径存在不存在?

临时文件何时清理,如何解决命名冲突,防止覆盖?

并发场景下的读写顺序如何保证?

……

对于读写物理文件带来的这些问题,最好的解决办法就是 不写文件 。然而,一些场景下想要不写文件可不那么容易,比如文件上传

二.问题

文件上传一般通过表单提交来实现,例如:

var FormData = require('form-data');var fs = require('fs');var form = new FormData();form.append('my_file', fs.createReadStream('/foo/bar.jpg'));form.submit('example.org/upload', function(err, res) { console.log(res.statusCode);});

(摘自 Form-Data )

不想写物理文件的话,可以这样做:

const FormData = require('form-data');const filename = 'my-file.txt';const content = 'balalalalala...变身';const formData = new FormData();// 1.先将字符串转换成Bufferconst fileContent = Buffer.from(content);// 2.补上文件meta信息formData.append('file', fileContent, { filename, contentType: 'text/plain', knownLength: fileContent.byteLength});

也就是说,文件流除了能够提供数据外,还具有一些 meta 信息,如文件名、文件路径等 ,而这些信息是普通 Stream 所不具备的。那么,有没有办法凭空创建一个“真正的”文件流?

三.思路

要想创建出“真正的”文件流,至少有正反 2 种思路:

给普通流添上文件相关的 meta 信息

先拿到一个真正的文件流,再改掉其数据和 meta 信息

显然,前者更灵活一些,并且实现上能够做到完全不依赖文件

文件流的生产过程

沿着凭空创造的思路,探究 fs.createReadStream API 的 内部实现 之后发现,生产文件流的关键过程如下:

function ReadStream(path, options) { // 1.打开path指定的文件 if (typeof this.fd !== 'number')  this.open();}ReadStream.prototype.open = function() { fs.open(this.path, this.flags, this.mode, (er, fd) => {  // 2.拿到文件描述符并持有  this.fd = fd;  this.emit('open', fd);  this.emit('ready');  // 3.开始流式读取数据  // read来自父类Readable,主要调用内部方法_read  // ref: https://github.com/nodejs/node/blob/v10.16.3/lib/_stream_readable.js#L390  this.read(); });};ReadStream.prototype._read = function(n) { // 4.从文件中读取一个chunk fs.read(this.fd, pool, pool.used, toRead, this.pos, (er, bytesRead) => {  let b = null;  if (bytesRead > 0) {   this.bytesRead += bytesRead;   b = thisPool.slice(start, start + bytesRead);  }  // 5.(通过触发data事件)吐出一个chunk,如果还有数据,process.nextTick再次this.read,直至this.push(null)触发'end'事件  // ref: https://github.com/nodejs/node/blob/v10.16.3/lib/_stream_readable.js#L207  this.push(b); });};            
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表

图片精选