聊聊 JS 的二进制家族:Blob、ArrayBuffer 和 Buffer

原文链接: 聊聊 JS 的二进制家族:Blob、ArrayBuffer 和 Buffer

上一篇: nodejs markdown 转 pdf

下一篇: 使用 jsperf 测试代码性能

https://zhuanlan.zhihu.com/p/97768916

概述

  • Blob : 前端的一个专门用于支持文件操作的二进制对象
  • ArrayBuffer :前端的一个通用的二进制缓冲区,类似数组,但在 API 和特性上却有诸多不同
  • Buffer :Node.js 提供的一个二进制缓冲区,常用来处理 I/O 操作

up-ea1e4d764f679854cd04d07ec08c5a5feb6.png

Blob

我们首先来介绍 Blob,Blob 是用来支持文件操作的。简单的说:在 JS 中,有两个构造函数 File 和 Blob, 而 File 继承了所有 Blob 的属性。

所以在我们看来,File 对象可以看作一种特殊的 Blob 对象。

在前端工程中,我们在哪些操作中可以获得 File 对象呢? 请看:

up-60456392bd5f9ae7ea99eab8dcab64f14ed.png

我们上面说了,File 对象是一种特殊的 Blob 对象,那么它自然就可以直接调用 Blob 对象的方法。让我们看一看 Blob 具体有哪些方法,以及能够用它们实现哪些功能

up-1fe360b2251cdb1d920fd9e0eb4515b228c.png

Blob 实战

通过 window.URL.createObjectURL 方法可以把一个 blob 转化为一个 Blob URL,并且用做文件下载或者图片显示的链接。

Blob URL 所实现的下载或者显示等功能,仅仅可以在单个浏览器内部进行。而不能在服务器上进行存储,亦或者说它没有在服务器端存储的意义。

下面是一个 Blob 的例子,可以看到它很短

blob:d3958f5c-0777-0845-9dcf-2cb28783acaf

和冗长的 Base64 格式的 Data URL 相比,Blob URL 的长度显然不能够存储足够的信息,这也就意味着它只是类似于一个浏览器内部的 “引用 “。从这个角度看,Blob URL 是一个浏览器自行制定的一个伪协议

Blob 实现下载文件

我们可以通过 window.URL.createObjectURL,接收一个 Blob(File)对象,将其转化为 Blob URL, 然后赋给 a.download 属性,然后在页面上点击这个链接就可以实现下载了

<!-- html部分 -->
<a id="h">点此进行下载</a>
<!-- js部分 -->
<script>
  var blob = new Blob(["Hello World"]);
  var url = window.URL.createObjectURL(blob);
  var a = document.getElementById("h");
  a.download = "helloworld.txt";
  a.href = url;
</script> 

(备注:download 属性不兼容 IE, 对 IE 可通过 window.navigator.msSaveBlob 方法或其他进行优化)

Blob 实现图片本地显示

window.URL.createObjectURL 生成的 Blob URL 还可以赋给 img.src,从而实现图片的显示

<!-- html部分 -->
<input type="file" id='f' />
<img id='img' style="width: 200px;height:200px;" />
<!-- js部分 -->
<script>
  document.getElementById('f').addEventListener('change', function (e) {
    var file = this.files[0];
    const img = document.getElementById('img');
    const url = window.URL.createObjectURL(file);
    img.src = url;
    img.onload = function () {
        // 释放一个之前通过调用 URL.createObjectURL创建的 URL 对象
        window.URL.revokeObjectURL(url);
    }
  }, false);
</script>

Blob 实现文件分片上传

  • 通过 Blob.slice (start,end) 可以分割大 Blob 为多个小 Blob
  • xhr.send 是可以直接发送 Blob 对象的

前端

<!-- html部分 -->
<input type="file" id='f' />
<!-- js部分 -->
<script>
function upload(blob) {
    var xhr = new XMLHttpRequest();
    xhr.open('POST', '/ajax', true);
    xhr.setRequestHeader('Content-Type', 'text/plain')
    xhr.send(blob);
}

document.getElementById('f').addEventListener('change', function (e) {
    var blob = this.files[0];
    const CHUNK_SIZE = 20; .
    const SIZE = blob.size;
    var start = 0;
    var end = CHUNK_SIZE;
    while (start < SIZE) {
        upload(blob.slice(start, end));
        start = end;
        end = start + CHUNK_SIZE;
    }
}, false);
</script>

Node 端 (Koa)

app.use(async (ctx, next) => {
    await next();
    if (ctx.path === '/ajax') {
        const req = ctx.req;
        const body = await parse(req);
        ctx.status = 200;
        console.log(body);
        console.log('---------------');
    }
});

文件内容

According to the Zhanjiang commerce bureau, the actual amount of foreign capital 
utilized in Zhanjiang from January to October this year was

本地读取文件内容

如果想要读取 Blob 或者文件对象并转化为其他格式的数据,可以借助 FileReader 对象的 API 进行操作

  • FileReader.readAsText(Blob) :将 Blob 转化为文本字符串
  • FileReader.readAsArrayBuffer(Blob) : 将 Blob 转为 ArrayBuffer 格式数据
  • FileReader.readAsDataURL() : 将 Blob 转化为 Base64 格式的 Data URL

下面我们尝试把一个文件的内容通过字符串的方式读取出来

<input type="file" id='f' />
<script>
  document.getElementById('f').addEventListener('change', function (e) {
    var file = this.files[0];
    const reader = new FileReader();
    reader.onload = function () {
        const content = reader.result;
        console.log(content);
    }
    reader.readAsText(file);
  }, false);
</script>

up-c23ca6cb09d24fed95008dd97803c3cdf23.png

上面介绍了 Blob 的用法,我们不难发现,Blob 是针对文件的,或者可以说它就是一个文件对象,同时呢我们发现 Blob 欠缺对二进制数据的细节操作能力,比如如果如果要具体修改某一部分的二进制数据,Blob 显然就不够用了,而这种细粒度的功能则可以由下面介绍的 ArrayBuffer 来完成。

ArrayBuffer

让我们用一张图看下 ArrayBuffer 的大体的功能

up-342d3a9bd6d5e4f35af015f3b552d9b9645.png

下面一一进行细节的介绍

ArrayBuffer 实战

通过 ArrayBuffer 的格式读取本地数据

document.getElementById('f').addEventListener('change', function (e) {
  const file = this.files[0];
  const fileReader = new FileReader();
  fileReader.onload = function () {
    const result = fileReader.result;
    console.log(result)
  }
  fileReader.readAsArrayBuffer(file);
}, false);

通过 ArrayBuffer 的格式读取 Ajax 请求数据

  • 通过 xhr.responseType = "arraybuffer" 指定响应的数据类型
  • 在 onload 回调里打印 xhr.response

前端

const xhr = new XMLHttpRequest();
xhr.open("GET", "ajax", true);
xhr.responseType = "arraybuffer";
xhr.onload = function () {
    console.log(xhr.response)
}
xhr.send();

Node 端

const app = new Koa();
app.use(async (ctx) => {
  if (pathname = '/ajax') {
    ctx.body = 'hello world';
    ctx.status = 200;
  }
}).listen(3000)

通过 TypeArray 对 ArrayBuffer 进行写操作

const typedArray1 = new Int8Array(8);
typedArray1[0] = 32;

const typedArray2 = new Int8Array(typedArray1);
typedArray2[1] = 42;

console.log(typedArray1);
//  output: Int8Array [32, 0, 0, 0, 0, 0, 0, 0]

console.log(typedArray2);
//  output: Int8Array [32, 42, 0, 0, 0, 0, 0, 0]

通过 DataView 对 ArrayBuffer 进行写操作

const buffer = new ArrayBuffer(16);
const view = new DataView(buffer);
view.setInt8(2, 42);
console.log(view.getInt8(2));
// 输出: 42

Buffer

Buffer 是 Node.js 提供的对象,前端没有。 它一般应用于 IO 操作,例如接收前端请求数据时候,可以通过以下的 Buffer 的 API 对接收到的前端数据进行整合

up-edd6c5b1c444a2adde8fc8ad0cfa724db91.png

Buffer 实战

例子如下

// Node端(Koa)
const app = new Koa();
app.use(async (ctx, next) => {
    if (ctx.path === '/ajax') {
        const chunks = [];
        const req = ctx.req;
        req.on('data', buf => {
            chunks.push(buf);
        })
        req.on('end', () => {
            let buffer = Buffer.concat(chunks);
            console.log(buffer.toString())
        })
    }
});
app.listen(3000)

// 前端
const xhr = new XMLHttpRequest();
xhr.open("POST", "ajax", true);
xhr.setRequestHeader('Content-Type', 'text/plain')
xhr.send("asdasdsadfsdfsadasdas");

运行结果

// Node端输出
asdasdsadfsdfsadasdas
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值