中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

深入nodejs中流(stream)的理解

發布時間:2020-10-24 00:27:18 來源:腳本之家 閱讀:210 作者:chshouyu 欄目:web開發

nodejs的fs模塊并沒有提供一個copy的方法,但我們可以很容易的實現一個,比如:

var source = fs.readFileSync('/path/to/source', {encoding: 'utf8'});
fs.writeFileSync('/path/to/dest', source);

這種方式是把文件內容全部讀入內存,然后再寫入文件,對于小型的文本文件,這沒有多大問題,比如grunt-file-copy就是這樣實現的。但是對于體積較大的二進制文件,比如音頻、視頻文件,動輒幾個GB大小,如果使用這種方法,很容易使內存“爆倉”。理想的方法應該是讀一部分,寫一部分,不管文件有多大,只要時間允許,總會處理完成,這里就需要用到流的概念。

深入nodejs中流(stream)的理解

如上面高大上的圖片所示,我們把文件比作裝水的桶,而水就是文件里的內容,我們用一根管子(pipe)連接兩個桶使得水從一個桶流入另一個桶,這樣就慢慢的實現了大文件的復制過程。

Stream在nodejs中是EventEmitter的實現,并且有多種實現形式,例如:

  • http responses request
  • fs read write streams
  • zlib streams
  • tcp sockets
  • child process stdout and stderr

上面的文件復制可以簡單實現一下:

var fs = require('fs');
var readStream = fs.createReadStream('/path/to/source');
var writeStream = fs.createWriteStream('/path/to/dest');

readStream.on('data', function(chunk) { // 當有數據流出時,寫入數據
  writeStream.write(chunk);
});

readStream.on('end', function() { // 當沒有數據時,關閉數據流
  writeStream.end();
});

上面的寫法有一些問題,如果寫入的速度跟不上讀取的速度,有可能導致數據丟失。正常的情況應該是,寫完一段,再讀取下一段,如果沒有寫完的話,就讓讀取流先暫停,等寫完再繼續,于是代碼可以修改為:

var fs = require('fs');
var readStream = fs.createReadStream('/path/to/source');
var writeStream = fs.createWriteStream('/path/to/dest');

readStream.on('data', function(chunk) { // 當有數據流出時,寫入數據
  if (writeStream.write(chunk) === false) { // 如果沒有寫完,暫停讀取流
    readStream.pause();
  }
});

writeStream.on('drain', function() { // 寫完后,繼續讀取
  readStream.resume();
});

readStream.on('end', function() { // 當沒有數據時,關閉數據流
  writeStream.end();
});

或者使用更直接的pipe

// pipe自動調用了data,end等事件
fs.createReadStream('/path/to/source').pipe(fs.createWriteStream('/path/to/dest'));

下面是一個更加完整的復制文件的過程

var fs = require('fs'),
  path = require('path'),
  out = process.stdout;

var filePath = '/Users/chen/Movies/Game.of.Thrones.S04E07.1080p.HDTV.x264-BATV.mkv';

var readStream = fs.createReadStream(filePath);
var writeStream = fs.createWriteStream('file.mkv');

var stat = fs.statSync(filePath);

var totalSize = stat.size;
var passedLength = 0;
var lastSize = 0;
var startTime = Date.now();

readStream.on('data', function(chunk) {

  passedLength += chunk.length;

  if (writeStream.write(chunk) === false) {
    readStream.pause();
  }
});

readStream.on('end', function() {
  writeStream.end();
});

writeStream.on('drain', function() {
  readStream.resume();
});

setTimeout(function show() {
  var percent = Math.ceil((passedLength / totalSize) * 100);
  var size = Math.ceil(passedLength / 1000000);
  var diff = size - lastSize;
  lastSize = size;
  out.clearLine();
  out.cursorTo(0);
  out.write('已完成' + size + 'MB, ' + percent + '%, 速度:' + diff * 2 + 'MB/s');
  if (passedLength < totalSize) {
    setTimeout(show, 500);
  } else {
    var endTime = Date.now();
    console.log();
    console.log('共用時:' + (endTime - startTime) / 1000 + '秒。');
  }
}, 500);

可以把上面的代碼保存為copy.js試驗一下

我們添加了一個遞歸的setTimeout(或者直接使用setInterval)來做一個旁觀者,每500ms觀察一次完成進度,并把已完成的大小、百分比和復制速度一并寫到控制臺上,當復制完成時,計算總的耗費時間,效果如圖:

深入nodejs中流(stream)的理解

我們復制了一集1080p的權利的游戲第四季第7集,大概3.78G大小,由于使用了SSD,可以看到速度還是非常不錯的,哈哈哈~ 復制完成后,顯示總花費時間

深入nodejs中流(stream)的理解

結合nodejs的readlineprocess.argv等模塊,我們可以添加覆蓋提示、強制覆蓋、動態指定文件路徑等完整的復制方法,有興趣的可以實現一下,實現完成,可以

ln -s /path/to/copy.js /usr/local/bin/mycopy

這樣就可以使用自己寫的mycopy命令替代系統的cp命令

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

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

宁晋县| 奎屯市| 翼城县| 郓城县| 沙湾县| 宁明县| 孝昌县| 建德市| 怀柔区| 新和县| 宁陵县| 兴和县| 西安市| 杭锦旗| 合山市| 景宁| 闽侯县| 五华县| 梁河县| 宁国市| 琼结县| 西藏| 鄂托克前旗| 庄浪县| 温宿县| 赫章县| 易门县| 彰化市| 松潘县| 合阳县| 普安县| 靖西县| 福鼎市| 微博| 象州县| 辉南县| 屏东市| 平江县| 西城区| 明溪县| 成都市|