本文介绍: 在 Web 开发中,当我们处理文件时(创建上传下载),经常会遇到二进制数据。另一个典型的应用场景图像处理。这些都可以通过 JavaScript 进行处理,而且二进制操作性能更高。不过,在 JavaScript 中有很多种二进制数据格式,会有点容易混淆

在 Web 开发中,当我们处理文件时(创建上传下载),经常会遇到二进制数据。另一个典型的应用场景图像处理
这些都可以通过 JavaScript 进行处理,而且二进制操作性能更高。
不过,在 JavaScript 中有很多种二进制数据格式,会有点容易混淆。仅举几个例子

ArrayBuffer 二进制数组

基本的二进制对象是 ArrayBuffer —— 对固定长度的连续内存空间引用

let buffer = new ArrayBuffer(16); // 创建一个长度为 16 的 buffer
alert(buffer.byteLength); // 16

它会分配一个 16 字节的连续内存空间,并用 0 进行预填充。
注意:ArrayBuffer 并不是一个数组,它只是一个连续的内存区域,仅仅用来暂存一下数据

操作 ArrayBuffer 中的数据

ArrayBuffer 核心对象,是所有的基础,是原始的二进制数据
如果要操作 ArrayBuffer,我们需要使用视图”对象。

视图对象本身并不存储任何东西。它是一副“眼镜”,透过它来解释存储在 ArrayBuffer 中的字节。同样的东西用不同的方式解析是不同的。
比如同样一个 16 字节 ArrayBuffer 中的二进制数据可以解释为 16 个“小数字”,或 8 个更大的数字(每个数字 2 个字节),或 4 个更大的数字(每个数字 4 个字节),或 2 个高精度浮点数(每个数字 8 个字节)。

类型视图

这里默认提供了几副固定视角的眼镜:

  • Uint8Array —— 将 ArrayBuffer 中的每个字节视为 0 到 255 之间的单个数字(每个字节是 8 位,因此只能容纳那么多)。这称为 “8 位无符号整数”。
  • Uint16Array —— 将每 2 个字节视为一个 0 到 65535 之间的整数。这称为 “16 位无符号整数”。
  • Uint32Array —— 将每 4 个字节视为一个 0 到 4294967295 之间的整数。这称为 “32 位无符号整数”。
  • Float64Array —— 将每 8 个字节视为一个 5.0x10-324 到 1.8x10308 之间的浮点数

DataView

DataView 是在 ArrayBuffer 上的一种特殊的超灵活“未类型化”视图。上面类型化的眼镜,一戴上视角固定了,所有的数据都已固定格式解析。而 DataView 这幅眼镜,视角是可调的,戴上后,想要什么视角就能调什么视角

TextDecoder 和 TextEncoder

内建的 TextDecoder 对象在给定缓冲区buffer)和编码格式(encoding)的情况下,允许将值读取为实际的 JavaScript 字符串

TextEncoder 做相反的事情 —— 将字符串转换为字节。

Blob

arrayBuffer,Uint8Array 及其他 BufferSource 是“二进制数据”,而 Blob表示具有类型的二进制数据”,比 arrBuffer 层级更高。
Blob类型,所以很容易解析对应文件可以将 Blob 看成某种文件的二进制形式。比如图片的二进制形式。
又因为 Blob 的类型通常是 MIME 类型,所以 Blob 对象很适用于浏览器上传/下载

XMLHttpRequest,fetch 等进行 Web 请求方法可以自然地使用 Blob,当然也可以使用其他类型的二进制数据。

我们可以轻松地在 Blob 和低级别的二进制数据类型之间进行转换

当我们需要处理大型 blob 时,将其转换stream 非常有用。你可以轻松地从 blob 创建 ReadableStream。Blob 接口stream() 方法返回一个 ReadableStream,其在被读取返回 blob 中包含的数据。

Blob 组成

Blob 由一个可选的字符串 type()和 blobParts 组成。blobParts 部分通常是一系列其他 Blob 对象,字符串 或 BufferSource
image.png
构造函数语法为:

new Blob(blobParts, options);
// 从字符串创建 Blob
let blob = new Blob(["<html>…</html>"], {type: 'text/html'});
// 请注意:第一个参数必须是一个数组 [...]

// 从类型化数组typed array)和字符串创建 Blob
let hello = new Uint8Array([72, 101, 108, 108, 111]); // 二进制格式的 "hello"
let blob = new Blob([hello, ' ', 'world'], {type: 'text/plain'});

Blob 操作

Blob 对象是不可改变的。
我们无法直接在 Blob 中更改数据,但我们可以通过 slice 获得 Blob 的多个部分,从这些部分创建新的 Blob 对象,将它们组成新的 Blob,等。就像字符串一样,无法只能更改内容,但可以拼接删除得到一个新字符串

用 slice 方法提取 Blob 片段:

blob.slice([byteStart], [byteEnd], [contentType]);

参数值类似于 array.slice,也允许是负数。

Blob 用作 URL 请求内容

URL.createObjectURL(blob)可以为在内存中的 Blob 创建一个唯一的 URL。URL 形式为 blob:<origin>/<uuid>
浏览器内部将 URL 和 Blob 形成映射关系通过这个短短的 URL 就可以访问到 Blob 了。这个 URL 用到, 等标签,Blob 数据就会作为请求内容下载

<!-- download 特性attribute)强制浏览器下载而不是导航 -->
<a download="hello.txt" href='#' id="link">Download</a>

<script>
  let blob = new Blob(["Hello, world!"], {type: 'text/plain'});

  link.href = URL.createObjectURL(blob);
</script>

点击 a 标签链接就会下载一个名为 hello.txt 的文件,文件内容为 hello, world!

有一个问题,Blob 始终存在内存中,当确认使用完后,我们可以手动指向它的引用,也就是创建的 URL 断开URL.revokeObjectURL(url)内部映射移除引用

Blob 转成 base64

除了使用URL.createObjectURL转成 URL 进行映射内存下载外,还可以将 Blob 数据转换base64-编码字符串数据。

我们使用内建的 FileReader 对象来将 Blob 转换base64。它可以将 Blob 中的数据读取为多种格式。

let link = document.createElement('a');
link.download = 'hello.txt';

let blob = new Blob(['Hello, world!'], {type: 'text/plain'});

let reader = new FileReader();
reader.readAsDataURL(blob); // 将 Blob 转换base64 并调用 onload

reader.onload = function() {
  link.href = reader.result; // data url
  link.click();
};

两种下载文件的方式对比:
URL.createObjectURL(blob):

Blob 转换data url

  • 无需撤销(revoke)任何操作。
  • 对大的 Blob 进行编码时,性能和内存会有损耗。

Image 转换为 blob 上传

我们可以创建一个图像image)的、图像的一部分、或者甚至创建一个页面截图的 Blob。这样方便将其上传至其他地方。

Blob 转换为 ArrayBuffer

Blob 构造器允许从几乎任何东西创建 blob,包括任何 BufferSource
但是,如果我们需要执行低级别的处理时,我们可以从 blob.arrayBuffer()获取最低级别的 ArrayBuffer:

// 从 bolb 获取 arrayBuffer
const bufferPromise = await blob.arrayBuffer();

// 或
blob.arrayBuffer().then(buffer => /* 处理 ArrayBuffer */);

Blob 转换为 Stream

什么是 stream 流?
流会将你想要从网络接受的资源分成一个个小的分块然后按位处理它。现在浏览器就是这么干的,看视频缓冲边继续看。
以前,如果我们想要处理某种资源(如视频、文本文件等),我们必须下载完整的文件,等待它反序列化成适当的格式,比如视频数据转成 mp4 格式,然后完整接收到所有的内容后再进行处理播放

当 blob 很大时,我们就可以转成 stream更好上传和下载。

Blob 接口里的 stream() 方法返回一个 ReadableStream,在被读取时可以返回 Blob 中包含的数据。

// 从 blob 获取可读流(readableStream
const readableStream = blob.stream();
const stream = readableStream.getReader();

while (true) {
  // 对于每次迭代value 是下一个 blob 数据片段
  let { done, value } = await stream.read();
  if (done) {
    // 读取完毕,stream 里已经没有数据了
    console.log('all blob processed.');
    break;
  }

  // 对刚从 blob 中读取的数据片段做一些处理
  console.log(value);
}

File 和 FileReader

File 对象继承自 Blob,并扩展了与文件系统相关功能。虽然 Blob 相对 ArrayBuffer 已经是高级对象了,但用起来还是不够方便,所以就有了更高级的对象。

获取 file 对象

有两种方式获取文件对象:

  1. 手动构造函数创建:new File(fileParts, fileName, [options])
  2. 操作系统提供,比如从 或拖放或其他浏览器接口来获取文件的时候操作系统就会提供文件的信息

由于 File 是继承自 Blob 的,所以 File 对象具有相同的属性,附加:

举个例子:我们从 中获取 File 对象的方式

<input type="file" onchange="showFile(this)">

<script>
function showFile(input) {
  let file = input.files[0];

  alert(`File name: ${file.name}`); // 例如 my.png
  alert(`Last modified: ${file.lastModified}`); // 例如 1552830408824
}
</script>

FileReader

FileReader 是一个对象,其唯一目的是从 Blob(因此也从 File)对象中读取数据
可以读取为以下三种格式:

但是,在很多情况下,我们不必读取文件内容。就像我们处理 blob 一样,我们可以使用 URL.createObjectURL(file) 创建一个短的 url,并将其赋给 或 。这样,文件便可以下载文件或者将其呈现为图像,作为 canvas 等的一部分

而且,如果我们要通过网络发送一个 File,那也很容易:像 XMLHttpRequest 或 fetch网络 API 本身就接受 File 对象。

https://zh.javascript.info/

原文地址:https://blog.csdn.net/qq_43220213/article/details/129329780

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_22328.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注