Node Buffer

Node Buffer

计算机中所有的内容:文字、数字、图片、音频、视频最终都会使用二进制来表示
JavaScript可以直接去处理非常直观的数据:比如字符串,通常展示给用户的也是这些内容
  1. 事实上在网页端,图片一直是交给浏览器来处理的
  2. JavaScript 或者 HTML,只是负责告诉浏览器一个图片的地址
  3. 浏览器负责获取这个图片,并且最终讲这个图片渲染出来
但是对于服务器来说是不一样的:
  1. 服务器要处理的本地文件类型相对较多;
  2. 比如某一个保存文本的文件并不是使用 utf-8 进行编码的,而是用 GBK,那么必须读取到他们的二进制数据,再通过 GKB 转换 成对应的文字
  3. 比如需要读取的是一张图片数据(二进制),再通过某些手段对图片数据进行二次的处理(裁剪、格式转换、旋转、添加滤 镜),Node中有一个Sharp的库,就是读取图片或者传入图片的Buffer对其再进行处理
  4. 比如在 Node 中通过 TCP 建立长连接,TCP传输的是字节流,需要将数据转成字节再进行传入,并且需要知道传输字节的大小 (客服端需要根据大小来判断读取多少内容)

Buffer 二进制

对于前端开发来说,通常很少会和二进制打交道,但是对于服务器端为了做很多的功能,必须直接去操 作其二进制的数据
Node为了可以方便开发者完成更多功能,提供给了一个类Buffer,并且它是全局的
Buffer中存储的是二进制数据,那么到底是如何存储?
  1. 可以将Buffer看成是一个存储二进制的数组
  2. 这个数组中的每一项,可以保存8位二进制: 00000000
8位
  1. 在计算机中,很少的情况会直接操作一位二进制,因为一位二进制存储的数据是非常有限的
  2. 所以通常会将8位合在一起作为一个单元,这个单元称之为一个字节(byte)
  3. 也就是说 1 byte = 8 bit,1 kb=1024 byte,1 M=1024 kb
  4. 比如很多编程语言中的 int 类型是4个字节,long 类型时8个字节
  5. 比如TCP传输的是字节流,在写入和读取时都需要说明字节的个数
  6. 比如 RGB 的值分别都是255,所以本质上在计算机中都是用一个字节存储的

Buffer 字符串

  • Buffer相当于是一个字节的数组,数组中的每一项对于一个字节的大小

  • 将一个字符串放入到Buffer中

    // const strbuffer = new Buffer('test') 废弃
    const strbuffer = Buffer.from('test')
    console.log(strbuffer)
    // <Buffer 74 65 73 74> t => 74 e => 65 s => 73 16进制
    
    字符串: test
    16进制数: 74 65 73 74
    buffer[74,65,73,74]
  • 默认编码:utf-8

    const strbuffer = Buffer.from('测试')
    console.log(strbuffer)
    // <Buffer e6 b5 8b e8 af 95> 一个中文对应三个字节
    
    // 编码
    const strbuffer = Buffer.from('测试', 'utf16le')
    // 解码
    console.log(strbuffer.toString('utf16le')) // 如果解码不同,可能会乱码
    
  • 其他创建方式

    // Static method: Buffer.alloc(size[, fill[, encoding]]) 内存分配
    const buffer = Buffer.alloc(8)
    console.log(buffer)
    // <Buffer 00 00 00 00 00 00 00 00>
    buffer[0] = 15
    buffer[1] = 0xf
    console.log(buffer)
    // <Buffer 0f 0f 00 00 00 00 00 00>
    

Buffer 文件读取

  1. 文本读取

    const fs = require('fs');
    
    fs.readFile('./test.txt', 'utf-8', (err, data) => { // 有编码
      console.log(data) // 123456789
    })
    
    fs.readFile('./test.txt', (err, data) => { // 没有编码
      console.log(data) // <Buffer 31 32 33 34 35 36 37 38 39>
    })
    
  2. 图片读取

    const fs = require('fs');
    
    fs.readFile('./unnamed.jpg', (err, data) => {
      fs.writeFile('./test.jpg', data, (err, data) => {
        console.log(err)
      })
    })
    

    图片处理 sharp

    const sharp = require('sharp')
    
    sharp('./unnamed.jpg')
      .resize(50, 50)
      .toFile('./test.jpg')
    

Buffer 创建过程

事实上创建Buffer时,并不会频繁的向操作系统申请内存,它会默认先申请一个 8 * 1024 个字节大小的内存, 也就是 8 kb

Buffer.poolSize = 8 * 1024; // 8kb
let poolSize, poolOffset, allocPool;

// A toggle used to access the zero fill setting of the array buffer allocator
// in C++.
// |zeroFill| can be undefined when running inside an isolate where we
// do not own the ArrayBuffer allocator.  Zero fill is always on in that case.
const zeroFill = bindingZeroFill || [0];

const encodingsMap = ObjectCreate(null);
for (let i = 0; i < encodings.length; ++i)
  encodingsMap[encodings[i]] = i;

function createUnsafeBuffer(size) {
  zeroFill[0] = 0;
  try {
    return new FastBuffer(size); // 创建 buffer
  } finally {
    zeroFill[0] = 1;
  }
}
// buffer.from
Buffer.from = function from(value, encodingOrOffset, length) {
  if (typeof value === 'string')
    return fromString(value, encodingOrOffset);

  if (typeof value === 'object' && value !== null) {
    if (isAnyArrayBuffer(value))
      return fromArrayBuffer(value, encodingOrOffset, length);

    const valueOf = value.valueOf && value.valueOf();
    if (valueOf != null &&
        valueOf !== value &&
        (typeof valueOf === 'string' || typeof valueOf === 'object')) {
      return from(valueOf, encodingOrOffset, length);
    }

    const b = fromObject(value);
    if (b)
      return b;

    if (typeof value[SymbolToPrimitive] === 'function') {
      const primitive = value[SymbolToPrimitive]('string');
      if (typeof primitive === 'string') {
        return fromString(primitive, encodingOrOffset);
      }
    }
  }

  throw new ERR_INVALID_ARG_TYPE(
    'first argument',
    ['string', 'Buffer', 'ArrayBuffer', 'Array', 'Array-like Object'],
    value
  );
};

// fromString
function fromString(string, encoding) {
  let ops;
  if (typeof encoding !== 'string' || encoding.length === 0) {
    if (string.length === 0)
      return new FastBuffer();
    ops = encodingOps.utf8;
    encoding = undefined;
  } else {
    ops = getEncodingOps(encoding);
    if (ops === undefined)
      throw new ERR_UNKNOWN_ENCODING(encoding);
    if (string.length === 0)
      return new FastBuffer();
  }
  return fromStringFast(string, ops);
}

// fromStringFast
function fromStringFast(string, ops) {
  const length = ops.byteLength(string);

  if (length >= (Buffer.poolSize >>> 1)) // 判断是否大于一半
    return createFromString(string, ops.encodingVal);

  if (length > (poolSize - poolOffset)) // 剩余空间不足够,通过 createPool 创建新的空间
    createPool();
  let b = new FastBuffer(allocPool, poolOffset, length);
  const actual = ops.write(b, string, 0, length);
  if (actual !== length) {
    // byteLength() may overestimate. That's a rare case, though.
    // 足够就直接使用,但是之后要进行 poolOffset的偏移变化
    b = new FastBuffer(allocPool, poolOffset, actual);
  }
  poolOffset += actual;
  alignPool();
  return b;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值