Skip to content

简单入门Buffer #167

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wuxianqiang opened this issue Jun 17, 2019 · 0 comments
Open

简单入门Buffer #167

wuxianqiang opened this issue Jun 17, 2019 · 0 comments

Comments

@wuxianqiang
Copy link
Owner

如果你第一次认识buffer,你可能会很陌生,因为在前端的JavaScript中并没有buffer,因为前端只要做一些字符串操作或DOM基本操作就能满足业务需求。

buffer是什么?

buffer是Node底层通过C++申请的内存,通过JS来分配内存。也就是存放文件的缓冲区。那么问题来了,为什么叫做缓存区,了解之前就要先跟大家科普一下V8的内存限制。

当我们在代码中声明变量并赋值时,所使用对象的内存就分配在堆中。如果已申请的堆空闲内存不够分配新的对象,将继续申请堆内存,直到堆的大小超过V8的限制为止。(64位系统下约为1.4 GB,32位系统下约为0.7 GB)

那么又为什么要限制,其实这样设计是有目的,方便V8做垃圾回收,在做垃圾回收时JS是停滞的,等待垃圾回收完成再恢复,所以垃圾回收的耗时关系到我们的性能,当内存太大就耗时越长,所以V8要这么限制。

在这样的限制下,将会导致Node无法直接操作大内存对象,比如无法将一个2 GB的文件读入内存中进行字符串分析处理,那么我们就将文件读取到buffer中,暂时存放,所以叫做缓冲区。

const fs = require('fs')

fs.readFile('./a.js', { encoding: 'utf8' }, (err, data) => {
  if (!err) {
    fs.writeFile('./b.js', data, { encoding: 'utf8' }, (err, data) => {
      if (err) {
        console.log('写入失败')
      }
    })
  } else {
    console.log('读取失败')
  }
})

不要使用fs.readFilesfs.writeFile直接进行大文件操作,而是使用 fs.createReadStreamfs.createWriteStream 方法通过流的方式实现对大文件的操作.

let reader = fs.createReadStream('a.js');
let writer = fs.createWriteStream('b.js');
reader.pipe(writer);

通过流的方式操作文件里面的原理也就是使用了buffer作为缓冲。每次读一点写一点。

虽然buffer是申请的内存,不受V8内存的限制,但是物理内存依然是有限的。

了解Buffer

Buffer是一个像Array的对象,但它主要用于操作字节

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

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

let buf = Buffer.from('hello', 'utf8')
console.log(buf)
// <Buffer 68 65 6c 6c 6f 20 77 6f 72 6c 64>
console.log(buf.length) // 5
console.log(buf[0]) // 104

可以访问 length 属性得到长度(表示的是字节的长度,在utf8编码中汉字是3字节,英文是1字节),也可以通过下标访问元素。

关于下标访问元素需要注意的是要经历一个计算的过程。我们通过获取第一个字母为例,首先是 h 根据ASCII码对照表查出来16进制是68,然后通过JS中的toString方法传入参数为2表示转换成二进制,得到1101000,然后再换成10进制的数就变成了104,所以通过下标访问的第一个元素结果是104,具体代码如下。

let buf = Buffer.from('hello', 'utf8')
console.log(buf)
// <Buffer 68 65 6c 6c 6f 20 77 6f 72 6c 64>
console.log((0x68).toString(2))
// 1101000

Buffer.from 的用法在这里介绍一下,第一个参数是字符串,表示创建一个包含字符串的buffer,第二个参数是指定字符的编码,默认值也是utf8

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant