最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Node.js從字符串生成文件流的實(shí)現(xiàn)方法

 更新時(shí)間:2019年08月18日 10:30:43   作者:黯羽輕揚(yáng)  
這篇文章主要介紹了Node.js從字符串生成文件流的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

一.背景

在文件相關(guān)的數(shù)據(jù)加工等場(chǎng)景下,經(jīng)常面臨生成的物理文件應(yīng)該如何處理的問(wèn)題,比如:

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

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

并發(fā)場(chǎng)景下的讀寫(xiě)順序如何保證?

……

對(duì)于讀寫(xiě)物理文件帶來(lái)的這些問(wèn)題,最好的解決辦法就是 不寫(xiě)文件 。然而,一些場(chǎng)景下想要不寫(xiě)文件可不那么容易,比如文件上傳

二.問(wèn)題

文件上傳一般通過(guò)表單提交來(lái)實(shí)現(xiàn),例如:

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

不想寫(xiě)物理文件的話,可以這樣做:

const FormData = require('form-data');

const filename = 'my-file.txt';
const content = 'balalalalala...變身';

const formData = new FormData();
// 1.先將字符串轉(zhuǎn)換成Buffer
const fileContent = Buffer.from(content);
// 2.補(bǔ)上文件meta信息
formData.append('file', fileContent, {
 filename,
 contentType: 'text/plain',
 knownLength: fileContent.byteLength
});

也就是說(shuō),文件流除了能夠提供數(shù)據(jù)外,還具有一些 meta 信息,如文件名、文件路徑等 ,而這些信息是普通 Stream 所不具備的。那么,有沒(méi)有辦法憑空創(chuàng)建一個(gè)“真正的”文件流?

三.思路

要想創(chuàng)建出“真正的”文件流,至少有正反 2 種思路:

給普通流添上文件相關(guān)的 meta 信息

先拿到一個(gè)真正的文件流,再改掉其數(shù)據(jù)和 meta 信息

顯然,前者更靈活一些,并且實(shí)現(xiàn)上能夠做到完全不依賴文件

文件流的生產(chǎn)過(guò)程

沿著憑空創(chuàng)造的思路,探究 fs.createReadStream API 的 內(nèi)部實(shí)現(xiàn) 之后發(fā)現(xiàn),生產(chǎn)文件流的關(guān)鍵過(guò)程如下:

function ReadStream(path, options) {
 // 1.打開(kāi)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.開(kāi)始流式讀取數(shù)據(jù)
  // read來(lái)自父類Readable,主要調(diào)用內(nèi)部方法_read
  // ref: https://github.com/nodejs/node/blob/v10.16.3/lib/_stream_readable.js#L390
  this.read();
 });
};

ReadStream.prototype._read = function(n) {
 // 4.從文件中讀取一個(gè)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.(通過(guò)觸發(fā)data事件)吐出一個(gè)chunk,如果還有數(shù)據(jù),process.nextTick再次this.read,直至this.push(null)觸發(fā)'end'事件
  // ref: https://github.com/nodejs/node/blob/v10.16.3/lib/_stream_readable.js#L207
  this.push(b);
 });
};

P.S.其中第 5 步相對(duì)復(fù)雜, this.push(buffer) 既能觸發(fā)下一個(gè) chunk 的讀?。?nbsp;this.read() ),也能在數(shù)據(jù)讀完之后(通過(guò) this.push(null) )觸發(fā) 'end' 事件,具體見(jiàn) node/lib/_stream_readable.js

重新實(shí)現(xiàn)文件流

既然已經(jīng)摸清了文件流的生產(chǎn)過(guò)程,下一步自然是 替換掉所有文件操作,直至文件流的實(shí)現(xiàn)完全不依賴文件 ,例如:

// 從文件中讀取一個(gè)chunk
fs.read(this.fd, pool, pool.used, toRead, this.pos, (er, bytesRead) => {
 /* ... */
});

// 換成
this._fakeReadFile(this.fd, pool, pool.used, toRead, this.pos, (bytesRead) => {
 /* ... */
});

// 從輸入字符串對(duì)應(yīng)的Buffer中copy出一個(gè)chunk
ReadStream.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 ,用來(lái)憑空創(chuàng)建文件流:

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

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 詳解nodeJS中讀寫(xiě)文件方法的區(qū)別

    詳解nodeJS中讀寫(xiě)文件方法的區(qū)別

    本篇文章主要介紹了詳解nodeJS中讀寫(xiě)文件方法的區(qū)別,nodejs的fs模塊針對(duì)讀操作為我們提供了readFile,read, createReadStream三個(gè)方法,有興趣的可以了解一下。
    2017-03-03
  • Nodejs讀取本地json文件,輸出json數(shù)據(jù)接口方式

    Nodejs讀取本地json文件,輸出json數(shù)據(jù)接口方式

    這篇文章主要介紹了Nodejs讀取本地json文件,輸出json數(shù)據(jù)接口方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • node.js中實(shí)現(xiàn)雙重身份驗(yàn)證機(jī)制的方法詳解

    node.js中實(shí)現(xiàn)雙重身份驗(yàn)證機(jī)制的方法詳解

    雙重身份驗(yàn)證(Two-factor?authentication)是一種安全機(jī)制,它要求用戶提供兩種不同的身份驗(yàn)證因素來(lái)訪問(wèn)他們的帳戶,下面我們就來(lái)學(xué)習(xí)一下如何使用speakeasy在nodejs中實(shí)現(xiàn)雙重身份驗(yàn)證吧
    2023-10-10
  • node中使用shell腳本的方法步驟

    node中使用shell腳本的方法步驟

    這篇文章主要介紹了node中使用shell腳本的方法步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • node.js中路由,中間件,get請(qǐng)求和post請(qǐng)求的參數(shù)詳解

    node.js中路由,中間件,get請(qǐng)求和post請(qǐng)求的參數(shù)詳解

    本文給大家匯總介紹了node.js中的路由,中間件,get請(qǐng)求和post請(qǐng)求的參數(shù)的使用方法,非常的詳細(xì),有需要的小伙伴可以參考下
    2017-12-12
  • Node.js 實(shí)現(xiàn)簡(jiǎn)單的接口服務(wù)器的實(shí)例代碼

    Node.js 實(shí)現(xiàn)簡(jiǎn)單的接口服務(wù)器的實(shí)例代碼

    這篇文章主要介紹了Node.js 實(shí)現(xiàn)簡(jiǎn)單的接口服務(wù)器的實(shí)例代碼,非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2017-05-05
  • 基于NodeJS開(kāi)發(fā)釘釘回調(diào)接口實(shí)現(xiàn)AES-CBC加解密

    基于NodeJS開(kāi)發(fā)釘釘回調(diào)接口實(shí)現(xiàn)AES-CBC加解密

    這篇文章主要介紹了基于NodeJS開(kāi)發(fā)釘釘回調(diào)接口 實(shí)現(xiàn)AES-CBC加解密,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • node.js將MongoDB數(shù)據(jù)同步到MySQL的步驟

    node.js將MongoDB數(shù)據(jù)同步到MySQL的步驟

    這篇文章主要給大家介紹了關(guān)于node.js將MongoDB數(shù)據(jù)同步到MySQL的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-12-12
  • node crawler如何添加promise支持

    node crawler如何添加promise支持

    這篇文章主要介紹了node crawler如何添加promise支持,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-02-02
  • node.js超時(shí)timeout詳解

    node.js超時(shí)timeout詳解

    本文介紹了nodejs中超時(shí)timeout事件,并給出了詳細(xì)的示例分析,非常的詳盡,推薦給需要的小伙伴參考下
    2014-11-11

最新評(píng)論

泽普县| 杂多县| 景东| 鹤峰县| 华坪县| 乡城县| 米脂县| 申扎县| 巴中市| 三亚市| 遂川县| 土默特右旗| 许昌市| 瑞昌市| 怀安县| 梓潼县| 利津县| 辽中县| 鄯善县| 焦作市| 河津市| 喀什市| 龙口市| 张家川| 漳平市| 沙雅县| 济阳县| 西和县| 榆中县| 微山县| 平原县| 六盘水市| 长岛县| 榆林市| 门头沟区| 南靖县| 柘城县| 子长县| 灵丘县| 修武县| 阜康市|