位置: 编程技术 - 正文

详解nodeJS之二进制buffer对象(nodejs init)

编辑:rootadmin

推荐整理分享详解nodeJS之二进制buffer对象(nodejs init),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:nodejs 2503,nodejs 2503,node读取二进制文件,node读取二进制文件,nodejs 2503,nodejs入口函数,nodejs进阶,node读取二进制文件,内容如对您有帮助,希望把文章链接给更多的朋友!

前面的话

在ES6引入TypedArray之前,JavaScript语言没有读取或操作二进制数据流的机制。Buffer类被引入作为Nodejs的API的一部分,使其可以在TCP流和文件系统操作等场景中处理二进制数据流。现在TypedArray已经被添加进ES6中,Buffer类以一种更优与更适合Node.js用例的方式实现了Uint8Array。本文将详细介绍buffer对象

概述

由于应用场景不同,在Node中,应用需要处理网络协议、操作数据库、处理图片、接收上传文件等,在网络流和文件的操作中,还要处理大量二进制数据,JavaScript自有的字符串远远不能满足这些需求,于是Buffer对象应运而生

Buffer是一个典型的JavaScript与C++结合的模块,它将性能相关部分用C++实现,将非性能相关的部分用JavaScript实现。Buffer类的实例类似于整数数组,除了其是大小固定的、且在V8堆外分配物理内存。Buffer的大小在其创建时就已确定,且不能调整大小

由于Buffer太过常见,Node在进程启动时就已经加载了它,并将其放在全局对象(global)上。所以在使用Buffer时,无须通过require()即可直接使用

创建

在 Node.js v6之前的版本中,Buffer实例是通过Buffer构造函数创建的,它根据提供的参数返回不同的 Buffer,而新版本的nodejs则提供了对应的方法

1、new Buffer(size)。传一个数值作为第一个参数给Buffer()(如new Buffer()),则分配一个指定大小的新建的Buffer对象

分配给这种Buffer实例的内存是未初始化的(没有用0填充)。虽然这样的设计使得内存的分配非常快,但已分配的内存段可能包含潜在的敏感旧数据

这种Buffer实例必须手动地被初始化,可以使用buf.fill(0)或写满这个Buffer。虽然这种行为是为了提高性能而有意为之的,但开发经验表明,创建一个快速但未初始化的Buffer与创建一个慢点但更安全的Buffer之间需要有更明确的区分

[注意]当我们为一个Buffer对象分配空间大小后,其长度就是固定的,不能更改

【Buffer.allocUnsafe(size)】

在新版本中,由Buffer.allocUnsafe(size)方法替代,来分配一个大小为 size 字节的新建的没有用0填充的Buffer。可以使用buf.fill(0)初始化Buffer实例为0

【Buffer.alloc(size[, fill[, encoding]])】

在新版本中,使用Buffer.alloc(size)方法可以生成一个安全的buffer对象,参数size <Integer> 新建的 Buffer 期望的长度;fill <String> | <Buffer> | <Integer> 用来预填充新建的 Buffer 的值。 默认: 0;encoding <String> 如果 fill 是字符串,则该值是它的字符编码。 默认: 'utf8'

分配一个大小为 size 字节的新建的 Buffer 。 如果 fill 为 undefined ,则该 Buffer 会用 0 填充

2、new Buffer(array或buffer)。传一个数组或Buffer作为第一个参数,则将所传对象的数据拷贝到Buffer

【Buffer.from(array或buffer)】

在新版本中,由Buffer.from(array或buffer)方法替代

3、new Buffer(string[, encoding])。第一个参数是字符串,第二个参数是编码方式,默认是'utf-8'

Node.js 目前支持的字符编码包括:

【Buffer.from(string[, encoding])】

在新版本中,由Buffer.from(string[, encoding]方法替代

4、new Buffer(arrayBuffer[, byteOffset [, length]])。参数arrayBuffer <ArrayBuffer> 一个 ArrayBuffer,或一个 TypedArray 的 .buffer 属性;byteOffset <Integer> 开始拷贝的索引。默认为 0;length <Integer> 拷贝的字节数。默认为 arrayBuffer.length - byteOffset

【Buffer.from(arrayBuffer[, byteOffset [, length]])】

在新版本中,由Buffer.from(arrayBuffer[, byteOffset [, length]])方法替代

类数组

Buffer对象类似于数组,它的元素为进制的两位数,即0到的数值

【长度】

不同编码的字符串占用的元素个数各不相同,中文字在UTF-8编码下占用3个元素,字母和半角标点符号占用1个元素

【下标】

Buffer受Array类型的影响很大,可以访问length属性得到长度,也可以通过下标访问元素

上述代码分配了一个长字节的Buffer对象。我们可以通过下标对它进行赋值

要注意的是,给元素的赋值如果小于0,就将该值逐次加,直到得到一个0到之间的整数。如果得到的数值大于,就逐次减,直到得到0~区间内的数值。如果是小数,舍弃小数部分,只保留整数部分

【fromcharcode】

通常地,创建的buffer对象的内容是其uft-8字符编码

如果要访问其对应的字符,则需要使用字符串的fromCharCode()方法

内存分配

Buffer对象的内存分配不是在V8的堆内存中,而是在Node的C++层面实现内存的申请的。因为处理大量的字节数据不能采用需要一点内存就向操作系统申请一点内存的方式,这可能造成大量的内存申请的系统调用,对操作系统有一定压力。为此Node在内存的使用上应用的是在C++层面申请内存、在JavaScript中分配内存的策略

为了高效地使用申请来的内存,Node采用了slab分配机制。slab是一种动态内存管理机制,最早诞生于SunOS操作系统(Solaris)中,目前在一些*nix操作系统中有广泛的应用,如FreeBSD和Linux。简单而言,slab就是一块申请好的固定大小的内存区域。slab具有如下3种状态:full:完全分配状态;partial:部分分配状态;empty:没有被分配状态

当我们需要一个Buffer对象,可以通过以下方式分配指定大小的Buffer对象:

【poolSize】

poolSize属性是用于决定预分配的、内部 Buffer 实例池的大小的字节数。默认地,Node以8KB为界限来区分Buffer是大对象还是小对象:

这个8KB的值也就是每个slab的大小值,在JavaScript层面,以它作为单位单元进行内存的分配

1、分配小Buffer对象

如果指定Buffer的大小少于8KB,Node会按照小对象的方式进行分配。Buffer的分配过程中主要使用一个局部变量pool作为中间处理对象,处于分配状态的slab单元都指向它。以下是分配一个全新的slab单元的操作,它会将新申请的SlowBuffer对象指向它:

构造小Buffer对象时的代码如下:

这次构造将会去检查pool对象,如果pool没有被创建,将会创建一个新的slab单元指向它:

同时当前Buffer对象的parent属性指向该slab,并记录下是从这个slab的哪个位置(offset)开始使用的,slab对象自身也记录被使用了多少字节,代码如下:

这时候的slab状态为partial。当再次创建一个Buffer对象时,构造过程中将会判断这个slab的剩余空间是否足够。如果足够,使用剩余空间,并更新slab的分配状态。下面的代码创建了一个新的Buffer对象,它会引起一次slab分配:

如果slab剩余的空间不够,将会构造新的slab,原slab中剩余的空间会造成浪费。例如,第一次构造1字节的Buffer对象,第二次构造字节的Buffer对象,由于第二次分配时slab中的空间不够,所以创建并使用新的slab,第一个slab的8KB将会被第一个1字节的Buffer对象独占。下面的代码一共使用了两个slab单元:

要注意的是,由于同一个slab可能分配给多个Buffer对象使用,只有这些小Buffer对象在作用域释放并都可以回收时,slab的8KB空间才会被回收。尽管创建了1个字节的Buffer对象,但是如果不释放它,实际可能是8KB的内存没有释放

2、分配大Buffer对象

如果需要超过8KB的Buffer对象,将会直接分配一个SlowBuffer对象作为slab单元,这个slab单元将会被这个大Buffer对象独占

这里的SlowBuffer类是在C++中定义的,虽然引用buffer模块可以访问到它,但是不推荐直接操作它,而是用Buffer替代

上面提到的Buffer对象都是JavaScript层面的,能够被V8的垃圾回收标记回收。但是其内部的parent属性指向的SlowBuffer对象却来自于Node自身C++中的定义,是C++层面上的Buffer对象,所用内存不在V8的堆中

综上,真正的内存是在Node的C++层面提供的,JavaScript层面只是使用它。当进行小而频繁的Buffer操作时,采用slab的机制进行预先申请和事后分配,使得JavaScript到操作系统之间不必有过多的内存申请方面的系统调用。对于大块的Buffer而言,则直接使用C++层面提供的内存,而无需细腻的分配操作

转换

Buffer对象可以与字符串之间相互转换。目前支持的字符串编码类型有如下几种:ASCII、UTF-8、UTF-LE/UCS-2、Base、Binary、Hex

【write()】

一个Buffer对象可以存储不同编码类型的字符串转码的值,调用write()方法可以实现该目的

  string <String> 要写入 buf 的字符串

  offset <Integer> 开始写入 string 的位置。默认: 0

  length <Integer> 要写入的字节数。默认: buf.length - offset

  encoding <String> string 的字符编码。默认: 'utf8';返回: <Integer> 写入的字节数

根据 encoding 的字符编码写入 string 到 buf 中的 offset 位置。 length 参数是写入的字节数。 如果 buf 没有足够的空间保存整个字符串,则只会写入 string 的一部分。 只部分解码的字符不会被写入

由于可以不断写入内容到Buffer对象中,并且每次写入可以指定编码,所以Buffer对象中可以存在多种编码转化后的内容。需要小心的是,每种编码所用的字节长度不同,将Buffer反转回字符串时需要谨慎处理

【toString()】

实现Buffer向字符串的转换也十分简单,Buffer对象的toString()可以将Buffer对象转换为字符串

  encoding - 使用的编码。默认为 'utf8'

  start - 指定开始读取的索引位置,默认为 0

  end - 结束位置,默认为缓冲区的末尾

详解nodeJS之二进制buffer对象(nodejs init)

  返回 - 解码缓冲区数据并使用指定的编码返回字符串

【toJSON()】

将 Node Buffer 转换为 JSON 对象

返回 buf 的 JSON 格式

【isEncoding()】

目前比较遗憾的是,Node的Buffer对象支持的编码类型有限,只有少数的几种编码类型可以在字符串和Buffer之间转换。为此,Buffer提供了一个isEncoding()函数来判断编码是否支持转换

将编码类型作为参数传入上面的函数,如果支持转换返回值为true,否则为false。很遗憾的是,在中国常用的GBK、GB和BIG-5编码都不在支持的行列中

类方法

【Buffer.byteLength(string[, encoding])】

Buffer.byteLength()方法返回一个字符串的实际字节长度。 这与 String.prototype.length 不同,因为那返回字符串的字符数

string <String> | <Buffer> | <TypedArray> | <DataView> | <ArrayBuffer> 要计算长度的值

encoding <String> 如果 string 是字符串,则这是它的字符编码。 默认: 'utf8'

返回: <Integer> string 包含的字节数

【Buffer.compare(buf1, buf2)】

该方法用于比较 buf1 和 buf2 ,通常用于 Buffer 实例数组的排序。 相当于调用 buf1.compare(buf2)

  buf1 <Buffer>

  buf2 <Buffer>

  Returns: <Integer>

【Buffer.concat(list[, totalLength])】

该方法返回一个合并了 list 中所有 Buffer 实例的新建的 Buffer

list <Array> 要合并的 Buffer 实例的数组

totalLength <Integer> 合并时 list 中 Buffer 实例的总长度

返回: <Buffer>

如果 list 中没有元素、或 totalLength 为 0 ,则返回一个新建的长度为 0 的 Buffer 。如果没有提供 totalLength ,则从 list 中的 Buffer 实例计算得到。 为了计算 totalLength 会导致需要执行额外的循环,所以提供明确的长度会运行更快

【Buffer.isBuffer(obj)】

如果 obj 是一个 Buffer 则返回 true ,否则返回 false

实例方法

【buf.slice([start[, end]])】

  该方法返回一个指向相同原始内存的新建的 Buffer,但做了偏移且通过 start 和 end 索引进行裁剪

  start <Integer> 新建的 Buffer 开始的位置。 默认: 0

  end <Integer> 新建的 Buffer 结束的位置(不包含)。 默认: buf.length

  返回: <Buffer>

[注意]修改这个新建的 Buffer 切片,也会同时修改原始的 Buffer 的内存,因为这两个对象所分配的内存是重叠的

【buf.copy(target[, targetStart[, sourceStart[, sourceEnd]]])】

  该方法用于拷贝 buf 的一个区域的数据到 target 的一个区域,即便 target 的内存区域与 buf 的重叠

  target <Buffer> | <Uint8Array> 要拷贝进的 Buffer 或 Uint8Array

  targetStart <Integer> target 中开始拷贝进的偏移量。 默认: 0

  sourceStart <Integer> buf 中开始拷贝的偏移量。 当 targetStart 为 undefined 时忽略。 默认: 0

  sourceEnd <Integer> buf 中结束拷贝的偏移量(不包含)。 当 sourceStart 为 undefined 时忽略。 默认: buf.length

  返回: <Integer> 被拷贝的字节数

【buf.compare(target[, targetStart[, targetEnd[, sourceStart[, sourceEnd]]]])】

  该方法比较 buf 与 target,返回表明 buf 在排序上是否排在 target 之前、或之后、或相同。 对比是基于各自 Buffer 实际的字节序列

  target <Buffer> 要比较的 Buffer

  targetStart <Integer> target 中开始对比的偏移量。 默认: 0

  targetEnd <Integer> target 中结束对比的偏移量(不包含)。 当 targetStart 为 undefined 时忽略。 默认: target.length

  sourceStart <Integer> buf 中开始对比的偏移量。 当 targetStart 为 undefined 时忽略。 默认: 0

  sourceEnd <Integer> buf 中结束对比的偏移量(不包含)。 当 targetStart 为 undefined 时忽略。 默认: buf.length

  返回: <Integer>

  如果 target 与 buf 相同,则返回 0

  如果 target 排在 buf 前面,则返回 1

  如果 target 排在 buf 后面,则返回 -1

【buf.equals(otherBuffer)】

  如果 buf 与 otherBuffer 具有完全相同的字节,则返回 true,否则返回 false

  otherBuffer <Buffer> 要比较的 Buffer

  返回: <Boolean>

【buf.fill(value[, offset[, end]][, encoding])】

  value <String> | <Buffer> | <Integer> 用来填充 buf 的值

  offset <Integer> 开始填充 buf 的位置。默认: 0

  end <Integer> 结束填充 buf 的位置(不包含)。默认: buf.length

  encoding <String> 如果 value 是一个字符串,则这是它的字符编码。 默认: 'utf8'

  返回: <Buffer> buf 的引用

  如果未指定 offset 和 end,则填充整个 buf。 这个简化使得一个Buffer的创建与填充可以在一行内完成

【buf.indexOf(value[, byteOffset][, encoding])】

  value <String> | <Buffer> | <Integer> 要搜索的值

  byteOffset <Integer> buf 中开始搜索的位置。默认: 0

  encoding <String> 如果 value 是一个字符串,则这是它的字符编码。 默认: 'utf8'

  返回: <Integer> buf 中 value 首次出现的索引,如果 buf 没包含 value 则返回 -1

  如果value是字符串,则 value 根据 encoding 的字符编码进行解析;如果value是Buffer,则value会被作为一个整体使用。如果要比较部分 Buffer 可使用 buf.slice();如果value是数值,则 value 会解析为一个 0 至 之间的无符号八位整数值

【buf.lastIndexOf(value[, byteOffset][, encoding])】

与 buf.indexOf() 类似,除了 buf 是从后往前搜索而不是从前往后

【buf.includes(value[, byteOffset][, encoding])】

该方法相当于 buf.indexOf() !== -1

  value <String> | <Buffer> | <Integer> 要搜索的值

  byteOffset <Integer> buf 中开始搜索的位置。默认: 0

  encoding <String> 如果 value 是一个字符串,则这是它的字符编码。 默认: 'utf8'

  返回: <Boolean> 如果 buf 找到 value,则返回 true,否则返回 false

标签: nodejs init

本文链接地址:https://www.jiuchutong.com/biancheng/380830.html 转载请保留说明!

上一篇:深入理解Nodejs Global 模块(深入理解计算机系统)

下一篇:npm国内镜像 安装失败的几种解决方案(npm镜像是什么意思)

  • 水利建设基金计费方式
  • 递延所得税资产和负债怎么理解
  • 未认证待抵扣进项税重分类
  • 京东佣金费用计算公式
  • 冲红重开发票增值税怎么处理
  • 非居民企业所得税税率10%
  • 固定资产贷款利率
  • 经营杠杆系数分类
  • 发票税表抵扣了账务未抵扣账务处理怎么做?
  • 母子公司之间的管理费可以税前扣除吗
  • 税控盘服务费怎么填写申报表
  • 广告费支出限额
  • 公司亏损没有收入怎么办
  • 企业如何规避印刷风险
  • 一般纳税人的工资可以抵扣吗
  • 专票密码区压线可以报销吗
  • 加油发票的票据抬头是个人,这样可报销吗?
  • 全员劳动生产率是什么意思
  • 小规模开税票怎么开
  • 公司没有实缴可以破产么
  • 结算会计和核算会计哪个更好
  • t3不能增加二级科目
  • 二手车过户员怎么样
  • 解决思路怎么写
  • 电脑xmp是啥
  • 教学用具属于什么项目类别
  • mmc.exe是什么进程
  • 内部收益率如何计算例题
  • 电脑麦克风没声音是什么原因
  • PHP简单实现HTTP和HTTPS跨域共享session解决办法
  • 财政返还土地奖金的规定
  • 波白克岛的小尖塔岩石,英格兰多塞特 (© James Osmond/Alamy)
  • 固定资产净残值率是多少
  • php显示错误报告方式
  • cookie from
  • 宝塔怎么做?
  • 销售发票重复开库存商品如何处理?
  • 会计月末账务处理方法
  • 一直暂估原材料有什么风险
  • 公司吸收合并流程详细步骤
  • 增值税税率调整为13%从什么时候开始实行
  • 固定资产报废时,后续未折旧额计入哪里
  • 动迁补偿金
  • 营改增后增加了什么征税项目
  • 住宿费开的增值税专用发票怎么记账
  • 建筑企业城建税和教育费附加怎么算
  • 公司注销时财务报表要注意什么
  • 搞活动的现金红包怎么用
  • 固定资产转售账务处理
  • 股权投资如何记账
  • 销售收入确认后怎么处理
  • 一般纳税人主表中的25是怎么来的
  • 公司银行开户的一些资料是公司办公室保存还是财务保存
  • 工程款结清确认书模板
  • 出纳和记账会计哪个好
  • 事业单位应设置事业收入科目
  • CentOS 7中安装mysql server的步骤分享
  • sql1068错误
  • 安装freebsd
  • 硬盘安装64位win8.1/win8或win7操作系统图文教程
  • 进程 cmd
  • win8.1 ie浏览器
  • 电脑操作系统win8
  • opengl纹理采样
  • react 技巧
  • perl中sub
  • ant编译工具
  • 获取nodejs命令行信息
  • nodejs xhr
  • 网络游戏数据包
  • 批处理删除重复值
  • nodejs dgram
  • python 字典的字典
  • unity移动
  • python中将字典转换为字符串
  • 面向对象的程序设计语言是
  • python tornado django
  • 税务稽查强制措施
  • 宁夏地税领导班子名单
  • 中国税务网官网1732171695993732.2418.61431871
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设