Nodejs Buffer拼接

本文記錄下最近遇到的buffer拼接問題。如果需要知道如何拼接 直接點擊第二節


1 背景

最近有一個需求需要將縮略圖和視頻文件合併到一起用HTTP POST 發送給服務器,服務器解析後拆成縮略圖和視頻文件存儲到雲存儲中。

於是就寫了下面這段代碼讀了讀取兩個文件,並相加。就實現下面這段代碼。

const fs = require('fs');
const http = require('http');
const thumbnail = fs.readFileSync('./20190306_00160734.jpg');
const video = fs.readFileSync('./20190306_00160734.MOV');

const bodyData =  thumbnail + video;//  thumbnail  + video;

console.info(`thumbnail length      :${thumbnail.length}`);
console.info(`video length          :${video.length}`);
console.info(`video+thumbnail length:${ video.length+thumbnail.length}`);
console.info(`result length         :${bodyData.length}`);

輸出:
thumbnail length      :103143
video length          :1193998
video+thumbnail length:1297141
result length         :1231302

結果發現兩個buffer相加後的變量大小比兩個變量大小的和更大, 黑人問號???
後面一想, fs.readFileSync 這東西讀出來的東西應該不是string 。** 這東西是一個buffer。
再一想, 依稀想到深入淺出nodejs裏面說過buffer不能拿着就開加
,而是有相應API(buffer.concat)去拼接。**

而如果直接用這個去做 加法 會發生什麼事呢?
Buffer1+Buffer2
兩個buffer 相加實質上是兩個buffer 轉成string 相加。
Buffer1.toString()+Buffer2.toString()
而爲什麼toString會出現這個問題呢?實質上歸根接地還是toString 編碼的原因造成:
toString 行爲默認編碼是UTF-8格式。而readFile 默認是沒有編碼的。


const fs = require('fs');
const http = require('http');
const thumbnail = fs.readFileSync('./20190306_00160734.jpg');
const video = fs.readFileSync('./20190306_00160734.MOV');
console.info(`thumbnail length       :${thumbnail.length}`);
console.info(`thumbnail string length:${thumbnail.toString().length}`);
console.info(`video length           :${video.length}`);
console.info(`video string length    :${video.toString().length}`);
輸出
thumbnail length       :103143
thumbnail string length:99410
video length           :1193998
video string length    :1131892

可以很明顯看到 Buffer toString(對2進制數據UTF8編碼後) 後length都發生了變化。數據長度變小了 。最終導致結果不對。

2 buffer拼接

Nodejs 提供了下面這個API 進行拼接

Buffer.concat(list[, totalLength])

list <Buffer[]> | <Uint8Array[]> 要合併的 Buffer 數組或 Uint8Array 數組。
totalLength <integer> 合併後 list 中的 Buffer 實例的總長度。
返回: <Buffer>
  
sample:
const buf1 = Buffer.alloc(10);
const buf2 = Buffer.alloc(14);
const buf3 = Buffer.alloc(18);
const totalLength = buf1.length + buf2.length + buf3.length;
console.log(totalLength);
// Prints: 42
const bufA = Buffer.concat([buf1, buf2, buf3], totalLength);
console.log(bufA);
// Prints: <Buffer 00 00 00 00 ...>
console.log(bufA.length);
// Prints: 42

使用上訴API,對縮略圖和video文件進行拼接後數據大小就正常了。


const fs = require('fs');
const http = require('http');
const thumbnail = fs.readFileSync('./20190306_00160734.jpg');
const video = fs.readFileSync('./20190306_00160734.MOV');
const bodyData1 = Buffer.concat([thumbnail, video], video.length+thumbnail.length);

console.info(`thumbnail length       :${thumbnail.length}`);
console.info(`video length           :${video.length}`);
console.info(`thumbnail+video  length:${thumbnail.length + video.length}`);
console.info(`concat length          :${bodyData1.length}`);
輸出
thumbnail length       :103143
video length           :1193998
thumbnail+video  length:1297141
concat length          :1297141

3 buffer 截取

這裏拼接成功後,發給服務器,服務器實質上也要進行buffer截取。提取出對應縮略圖和video 調用的是下面的API:
buffur.slice API:

buf.slice([start[, end]])
start <integer>新的Buffer開始位置。默認值: 0。
end <integer>新的Buffer終止處(不包括在內)。 默認值: buf.length。
返回:<Buffer>
返回一個新Buffer引用,該引用與原始引用相同的內存,但由start和end索引偏移並裁剪。

測試代碼

var fs = require('fs');
const videoFile = fs.readFileSync('./20190306_00160734.MOV');
var video = Buffer.from(videoFile);
console.info(video.length);
var video1 = video.slice(0, 500000); 
var video2 = video.slice(500000, 1000000); 
var video3 = video.slice(1000000); 
console.log(video1.length);
console.log(video2.length);
console.log(video3.length);
const videoAll  = Buffer.concat([video1, video2, video3], video1.length + video2.length + video3.length);
fs.writeFileSync('./test.MOV', videoAll);
// 1193998
// 500000
// 500000
// 193998


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章