国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發 > JS > 正文

Node.js從字符串生成文件流的實現方法

2024-05-06 16:54:19
字體:
來源:轉載
供稿:網友

一.背景

在文件相關的數據加工等場景下,經常面臨生成的物理文件應該如何處理的問題,比如:

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

臨時文件何時清理,如何解決命名沖突,防止覆蓋?

并發場景下的讀寫順序如何保證?

……

對于讀寫物理文件帶來的這些問題,最好的解決辦法就是 不寫文件 。然而,一些場景下想要不寫文件可不那么容易,比如文件上傳

二.問題

文件上傳一般通過表單提交來實現,例如:

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); });};

P.S.其中第 5 步相對復雜, this.push(buffer) 既能觸發下一個 chunk 的讀取( this.read() ),也能在數據讀完之后(通過 this.push(null) )觸發 'end' 事件,具體見 node/lib/_stream_readable.js

重新實現文件流

既然已經摸清了文件流的生產過程,下一步自然是 替換掉所有文件操作,直至文件流的實現完全不依賴文件 ,例如:

// 從文件中讀取一個chunkfs.read(this.fd, pool, pool.used, toRead, this.pos, (er, bytesRead) => { /* ... */});// 換成this._fakeReadFile(this.fd, pool, pool.used, toRead, this.pos, (bytesRead) => { /* ... */});// 從輸入字符串對應的Buffer中copy出一個chunkReadStream.prototype._fakeReadFile = function(_, buffer, offset, length, position, cb) { position = position || this.input._position; // fake read file async setTimeout(() => {  let bytesRead = 0;  if (position < this.input.byteLength) {   bytesRead = this.input.copy(buffer, offset, position, position + length - 1);   this.input._position += bytesRead;  }  cb(bytesRead); }, 0);}

即從中剔除文件操作,用基于字符串的操作去替代它們

四.解決方案

如此這般,就有了 ayqy/string-to-file-stream ,用來憑空創建文件流:

string2fileStream('string-content') === fs.createReadStream(/* path to a text file with content 'string-content' */)`

例如:

const string2fileStream = require('string-to-file-stream');const input = 'Oh, my great data!';const s = string2fileStream(input);s.on('data', (chunk) => { assert.equal(chunk.toString(), input);});生成的流同樣能夠具有文件 meta 信息:const string2fileStream = require('string-to-file-stream');const formData = new FormData();formData.append('file', string2fileStream('my-string-data', { path: './abc.txt' }));form.submit('example.org/upload', function(err, res) { console.log(res.statusCode);});

足夠以假亂真

參考資料

fs.createReadStream(path[, options])

fs/streams.js

_stream_readable.js

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VeVb武林網。


注:相關教程知識閱讀請移步到JavaScript/Ajax教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: SHOW| 钦州市| 藁城市| 灌阳县| 漠河县| 若羌县| 深泽县| 光泽县| 福州市| 木里| 漳浦县| 吉木萨尔县| 都江堰市| 安义县| 开封市| 镇雄县| 营口市| 桐柏县| 阿尔山市| 周口市| 乌鲁木齐市| 尼勒克县| 浙江省| 嘉峪关市| 万盛区| 隆回县| 福州市| 漳平市| 咸宁市| 城固县| 赤城县| 鄱阳县| 涪陵区| 巴彦淖尔市| 太康县| 桑日县| 铁力市| 荣成市| 黄平县| 马公市| 淳安县|