博客列表 >Nodejs Buffer拼接

Nodejs Buffer拼接

弘德誉曦的博客
弘德誉曦的博客原创
2019年11月25日 11:39:401386浏览

文章目录

  • 1 背景
  • 2 buffer拼接
  • 3 buffer 截取

1 背景

最近有一个需求需要将缩略图和视频文件合并到一起用HTTP POST 发送给服务器,服务器解析后拆成缩略图和视频文件存储到云存储中。

于是就写了下面这段代码读了读取两个文件,并相加。就实现下面这段代码。

  1. const fs = require('fs');
  2. const http = require('http');
  3. const thumbnail = fs.readFileSync('./20190306_00160734.jpg');
  4. const video = fs.readFileSync('./20190306_00160734.MOV');
  5. const bodyData = thumbnail + video;// thumbnail + video;
  6. console.info(`thumbnail length :${thumbnail.length}`);
  7. console.info(`video length :${video.length}`);
  8. console.info(`video+thumbnail length:${ video.length+thumbnail.length}`);
  9. console.info(`result length :${bodyData.length}`);
  10. 输出:
  11. thumbnail length :103143
  12. video length :1193998
  13. video+thumbnail length:1297141
  14. 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 默认是没有编码的。

  1. const fs = require('fs');
  2. const http = require('http');
  3. const thumbnail = fs.readFileSync('./20190306_00160734.jpg');
  4. const video = fs.readFileSync('./20190306_00160734.MOV');
  5. console.info(`thumbnail length :${thumbnail.length}`);
  6. console.info(`thumbnail string length:${thumbnail.toString().length}`);
  7. console.info(`video length :${video.length}`);
  8. console.info(`video string length :${video.toString().length}`);
  9. 输出
  10. thumbnail length :103143
  11. thumbnail string length:99410
  12. video length :1193998
  13. video string length :1131892

可以很明显看到 Buffer toString(对2进制数据UTF8编码后) 后length都发生了变化。数据长度变小了 。最终导致结果不对。

2 buffer拼接

Nodejs 提供了下面这个API 进行拼接

  1. Buffer.concat(list[, totalLength])
  2. list <Buffer[]> | <Uint8Array[]> 要合并的 Buffer 数组或 Uint8Array 数组。
  3. totalLength <integer> 合并后 list 中的 Buffer 实例的总长度。
  4. 返回: <Buffer>
  5. sample
  6. const buf1 = Buffer.alloc(10);
  7. const buf2 = Buffer.alloc(14);
  8. const buf3 = Buffer.alloc(18);
  9. const totalLength = buf1.length + buf2.length + buf3.length;
  10. console.log(totalLength);
  11. // Prints: 42
  12. const bufA = Buffer.concat([buf1, buf2, buf3], totalLength);
  13. console.log(bufA);
  14. // Prints: <Buffer 00 00 00 00 ...>
  15. console.log(bufA.length);
  16. // Prints: 42

使用上诉API,对缩略图和video文件进行拼接后数据大小就正常了。

  1. const fs = require('fs');
  2. const http = require('http');
  3. const thumbnail = fs.readFileSync('./20190306_00160734.jpg');
  4. const video = fs.readFileSync('./20190306_00160734.MOV');
  5. const bodyData1 = Buffer.concat([thumbnail, video], video.length+thumbnail.length);
  6. console.info(`thumbnail length :${thumbnail.length}`);
  7. console.info(`video length :${video.length}`);
  8. console.info(`thumbnail+video length:${thumbnail.length + video.length}`);
  9. console.info(`concat length :${bodyData1.length}`);
  10. 输出
  11. thumbnail length :103143
  12. video length :1193998
  13. thumbnail+video length:1297141
  14. concat length :1297141

3 buffer 截取

这里拼接成功后,发给服务器,服务器实质上也要进行buffer截取。提取出对应缩略图和video 调用的是下面的API:

  1. Buffer.from(arrayBuffer[, byteOffset[, length]])
  2. arrayBuffer <ArrayBuffer> | <SharedArrayBuffer> 一个 ArrayBufferSharedArrayBuffer、或 TypedArray .buffer 属性。
  3. byteOffset <integer> 开始拷贝的索引。默认值: 0
  4. length <integer> 拷贝的字节数。默认值: arrayBuffer.length - byteOffset
  5. const ab = new ArrayBuffer(10);
  6. const buf = Buffer.from(ab, 0, 2);
  7. console.log(buf.length);

实例

比如通过下面方式接受HTTP Body 中内容.
下面代码分段接受数据 通过,数组方式暂存各段数据,再使用concat 拼接数据。
这里比较关键的是Buffer.from(arrayBuffer[, byteOffset[, length]]) API 接受参数是arrayBuffer。
concat API 返回的是buffer, 所以这里要用 Buffer.buffer 把Buffer转换成ArrayBuffer。

  1. let trunks = [];
  2. let trunksLength = 0;
  3. req.on('data',function(trunk){
  4. trunks.push(trunk); //Data: video + thumbnail Size: video.length
  5. trunksLength+=trunk.length;
  6. }).on('end',function(){
  7. logger.info(trunksLength);
  8. const uploadFileData = Buffer.concat(trunks, trunksLength);
  9. const viodeBuffer = Buffer.from(uploadFileData.buffer, 0, req.headers.size);
  10. const thumbnailBuffer = Buffer.from(uploadFileData.buffer, req.headers.size);
  11. });
声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议