谈谈JS二进制:File、Blob、FileReader、ArrayBuffer、Base64(上)

简介: 谈谈JS二进制:File、Blob、FileReader、ArrayBuffer、Base64(上)

JavaScript 提供了一些 API 来处理文件或原始文件数据,例如:File、Blob、FileReader、ArrayBuffer、base64 等。下面就来看看它们都是如何使用的,它们之间又有何区别和联系。0000000000000000000000000000000000000.webp.jpg


1. Blob


Blob 全称为 binary large object ,即二进制大对象,它是 JavaScript 中的一个对象,表示原始的类似文件的数据。下面是 MDN 中对 Blob 的解释:

Blob 对象表示一个不可变、原始数据的类文件对象。它的数据可以按文本或二进制的格式进行读取,也可以转换成 ReadableStream 来用于数据操作。

实际上,Blob 对象是包含有只读原始数据的类文件对象。简单来说,Blob 对象就是一个不可修改的二进制文件。

(1)Blob 创建

可以使用 Blob() 构造函数来创建一个 Blob:


newBlob(array, options);

其有两个参数:

  • array:由 ArrayBufferArrayBufferViewBlobDOMString 等对象构成的,将会被放进 Blob
  • options:可选的 BlobPropertyBag 字典,它可能会指定如下两个属性
  • type:默认值为 "",表示将会被放入到 blob 中的数组内容的 MIME 类型。
  • endings:默认值为"transparent",用于指定包含行结束符\n的字符串如何被写入,不常用。

常见的 MIME 类型如下:

MIME 类型 描述
text/plain 纯文本文档
text/html HTML 文档
text/javascript JavaScript 文件
text/css CSS 文件
application/json JSON文件
application/pdf PDF文件
application/xml XML 文件
image/jpeg JPEG图像
image/png PNG图像
image/gif GIF 图像
image/svg+xml SVG 图像
audio/mpeg MP3 文件
video/mpeg MP4 文件

下面来看一个简单的例子:


const blob = newBlob(["Hello World"], {type: "text/plain"});

这里可以成为动态文件创建,其正在创建一个类似文件的对象。这个 blob 对象上有两个属性:

  • size:Blob对象中所包含数据的大小(字节);
  • type:字符串,认为该Blob对象所包含的 MIME 类型。如果类型未知,则为空字符串。

下面来看打印结果:

const blob = new Blob(["Hello World"], {type: "text/plain"});
console.log(blob.size); // 11
console.log(blob.type); // "text/plain"

注意,字符串"Hello World"是 UTF-8 编码的,因此它的每个字符占用 1 个字节。

到现在,Blob 对象看起来似乎我们还是没有啥用。那该如何使用 Blob 对象呢?可以使用 URL.createObjectURL() 方法将将其转化为一个 URL,并在 Iframe 中加载:

javascript

<iframe></iframe>
const iframe = document.getElementsByTagName("iframe")[0];
const blob = new Blob(["Hello World"], {type: "text/plain"});
iframe.src = URL.createObjectURL(blob);

(2)Blob 分片

除了使用Blob()构造函数来创建blob 对象之外,还可以从 blob 对象中创建blob,也就是将 blob 对象切片。Blob 对象内置了 slice() 方法用来将 blob 对象分片,其语法如下:

javascript

复制代码

const blob = instanceOfBlob.slice([start [, end [, contentType]]]};

其有三个参数:

  • start:设置切片的起点,即切片开始位置。默认值为 0,这意味着切片应该从第一个字节开始;
  • end:设置切片的结束点,会对该位置之前的数据进行切片。默认值为blob.size
  • contentType:设置新 blob 的 MIME 类型。如果省略 type,则默认为 blob 的原始值。

下面来看例子:

const iframe = document.getElementsByTagName("iframe")[0];
const blob = new Blob(["Hello World"], {type: "text/plain"});
const subBlob = blob.slice(0, 5);
iframe.src = URL.createObjectURL(subBlob);

此时页面会显示"Hello"。


2. File


文件(File)接口提供有关文件的信息,并允许网页中的 JavaScript 访问其内容。实际上,File 对象是特殊类型的 Blob,且可以用在任意的 Blob 类型的 context 中。Blob 的属性和方法都可以用于 File 对象。

注意:File 对象中只存在于浏览器环境中,在 Node.js 环境中不存在。

在 JavaScript 中,主要有两种方法来获取 File 对象:

  • 元素上选择文件后返回的 FileList 对象;
  • 文件拖放操作生成的 DataTransfer 对象;

(1)input

首先定义一个输入类型为 file 的 input 标签:

javascript

复制代码

"file" id="fileInput" multiple="multiple">

这里给 input 标签添加了三个属性:

  • type="file":指定 input 的输入类型为文件;
  • id="fileInput":指定 input 的唯一 id;
  • multiple="multiple":指定 input 可以同时上传多个文件;

下面来给 input 标签添加 onchange 事件,当选择文件并上传之后触发:

javascript

复制代码

const fileInput = document.getElementById("fileInput");

fileInput.onchange = (e) => {    console.log(e.target.files);}

当点击上传文件时,控制台就会输出一个 FileList 数组,这个数组的每个元素都是一个 File 对象,一个上传的文件就对应一个 File 对象:5.webp.jpg每个 File 对象都包含文件的一些属性,这些属性都继承自 Blob 对象:

  • lastModified:引用文件最后修改日期,为自1970年1月1日0:00以来的毫秒数;
  • lastModifiedDate:引用文件的最后修改日期;
  • name:引用文件的文件名;
  • size:引用文件的文件大小;
  • type:文件的媒体类型(MIME);
  • webkitRelativePath:文件的路径或 URL。

通常,我们在上传文件时,可以通过对比 size 属性来限制文件大小,通过对比 type 来限制上传文件的格式等。

(2)文件拖放

另一种获取 File 对象的方式就是拖放 API,这个 API 很简单,就是将浏览器之外的文件拖到浏览器窗口中,并将它放在一个成为拖放区域的特殊区域中。拖放区域用于响应放置操作并从放置的项目中提取信息。这些是通过 ondropondragover 两个 API 实现的。

下面来看一个简单的例子,首先定义一个拖放区域:

const dropZone = document.getElementById("drop-zone");
dropZone.ondragover = (e) => {
    e.preventDefault();
}
dropZone.ondrop = (e) => {
    e.preventDefault();
    const files = e.dataTransfer.files;
    console.log(files)
}

注意:这里给两个 API 都添加了 e.preventDefault(),用来阻止默认事件。它是非常重要的,可以用来阻止浏览器的一些默认行为,比如放置文件将显示在浏览器窗口中。

当拖放文件到拖放区域时,控制台就会输出一个  FileList 数组,该数组的每一个元素都是一个 File 对象。这个 FileList 数组是从事件参数的 dataTransfer 属性的 files 获取的:6.webp.jpg可以看到,这里得到的 File 对象和通过 input 标签获得的 File 对象是完全一样的。


3. FileReader


FileReader 是一个异步 API,用于读取文件并提取其内容以供进一步使用。FileReader 可以将 Blob 读取为不同的格式。

注意:FileReader 仅用于以安全的方式从用户(远程)系统读取文件内容,不能用于从文件系统中按路径名简单地读取文件。

(1)基本使用

可以使用 FileReader 构造函数来创建一个 FileReader 对象:

javascript

复制代码

const reader = newFileReader();

这个对象常用属性如下:

  • error:表示在读取文件时发生的错误;
  • result:文件内容。该属性仅在读取操作完成后才有效,数据的格式取决于使用哪个方法来启动读取操作。
  • readyState:表示FileReader状态的数字。取值如下: | 常量名 | | 描述 | | --- | --- | --- | | EMPTY | 0 | 还没有加载任何数据。 | | LOADING | 1 | 数据正在被加载。 | | DONE | 2 | 已完成全部的读取请求。 |

FileReader 对象提供了以下方法来加载文件:

  • readAsArrayBuffer():读取指定 Blob 中的内容,完成之后,result 属性中保存的将是被读取文件的 ArrayBuffer 数据对象;
  • FileReader.readAsBinaryString():读取指定 Blob 中的内容,完成之后,result 属性中将包含所读取文件的原始二进制数据;
  • FileReader.readAsDataURL():读取指定 Blob 中的内容,完成之后,result 属性中将包含一个data: URL 格式的 Base64 字符串以表示所读取文件的内容。
  • FileReader.readAsText():读取指定 Blob 中的内容,完成之后,result 属性中将包含一个字符串以表示所读取的文件内容。

可以看到,上面这些方法都接受一个要读取的 blob 对象作为参数,读取完之后会将读取的结果放入对象的 result 属性中。

(2)事件处理

FileReader 对象常用的事件如下:

  • abort:该事件在读取操作被中断时触发;
  • error:该事件在读取操作发生错误时触发;
  • load:该事件在读取操作完成时触发;
  • progress:该事件在读取 Blob 时触发。

当然,这些方法可以加上前置 on 后在HTML元素上使用,比如onloadonerroronabortonprogress。除此之外,由于FileReader对象继承自EventTarget,因此还可以使用 addEventListener() 监听上述事件。

下面来看一个简单的例子,首先定义一个 input 输入框用于上传文件:

const fileInput = document.getElementById("fileInput");
const reader = new FileReader();
fileInput.onchange = (e) => {
    reader.readAsText(e.target.files[0]);
}
reader.onload = (e) => {
    console.log(e.target.result);
}

这里,首先创建了一个 FileReader 对象,当文件上传成功时,使用 readAsText() 方法读取 File 对象,当读取操作完成时打印读取结果。

使用上述例子读取文本文件时,就是比较正常的。如果读取二进制文件,比如png格式的图片,往往会产生乱码,如下:

4.webp.jpg

那该如何处理这种二进制数据呢?readAsDataURL() 是一个不错的选择,它可以将读取的文件的内容转换为 base64 数据的 URL 表示。这样,就可以直接将 URL 用在需要源链接的地方,比如 img 标签的 src 属性。

对于上述例子,将 readAsText 方法改为 readAsDataURL()

const fileInput = document.getElementById("fileInput");
const reader = new FileReader();
fileInput.onchange = (e) => {
    reader.readAsDataURL(e.target.files[0]);
}
reader.onload = (e) => {
    console.log(e.target.result);
}

这时,再次上传二进制图片时,就会在控制台打印一个 base64 编码的 URL,如下:

3.webp.jpg

下面来修改一下这个例子,将上传的图片通过以上方式显示在页面上:

<input type="file" id="fileInput" />
<img id="preview" />
const fileInput = document.getElementById("fileInput");
const preview = document.getElementById("preview");
const reader = new FileReader();
fileInput.onchange = (e) => {
  reader.readAsDataURL(e.target.files[0]);
};
reader.onload = (e) => {
  preview.src = e.target.result;
  console.log(e.target.result);
};

2.webp.jpg

当上传大文件时,可以通过 progress 事件来监控文件的读取进度:

const reader = new FileReader();
reader.onprogress = (e) => {
  if (e.loaded && e.total) {
    const percent = (event.loaded / event.total) * 100;
    console.log(`上传进度: ${Math.round(percent)} %`);
  }
});

progress 事件提供了两个属性:loaded(已读取量)和total(需读取总量)。


谈谈JS二进制:File、Blob、FileReader、ArrayBuffer、Base64(下)https://developer.aliyun.com/article/1411386


相关文章
|
1月前
|
存储 开发框架 JavaScript
uniapp、vue、小程序、js图片转base64 示例代码
uniapp、vue、小程序、js图片转base64 示例代码
69 0
|
1月前
|
前端开发 JavaScript 数据安全/隐私保护
JavaScript 中的二进制散列值和权限设计
这篇文章介绍了JavaScript中使用位运算符进行权限控制的方法。文章首先介绍了JavaScript中的进制类型,包括十进制、二进制、十六进制和八进制。然后解释了位运算符的概念和常用的按位与、按位或、按位异或和按位非操作符。接下来讨论了位运算符在传统权限系统中的应用场景,并给出了一个基于二进制变量表示权限的示例。最后,文章提到了位运算符方案的局限性,例如每个权限码必须是唯一且只有一位为1的限制。但总的来说,在中小型业务中可以使用这种方式进行权限控制。
|
26天前
|
前端开发 JavaScript PHP
解决在页面中无法获取qrcode.js生成的base64的图片
该文档介绍了如何解决在部分安卓手机上无法正确加载二维码图片的问题。之前的方法是使用qrcode.js生成二维码,然后与背景图结合用canvas绘制海报,但在某些安卓设备上遇到onload事件不触发的问题。
28 2
|
1月前
|
编解码 JavaScript 前端开发
【专栏】介绍了字符串Base64编解码的基本原理和在Java、Python、C++、JavaScript及Go等编程语言中的实现示例
【4月更文挑战第29天】本文介绍了字符串Base64编解码的基本原理和在Java、Python、C++、JavaScript及Go等编程语言中的实现示例。Base64编码将24位二进制数据转换为32位可打印字符,用“=”作填充。文中展示了各语言的编码解码代码,帮助开发者理解并应用于实际项目。
|
1月前
|
JavaScript 前端开发 数据处理
掌握JavaScript中的二进制运算,提升你的编程技能!
掌握JavaScript中的二进制运算,提升你的编程技能!
|
1月前
|
存储 自然语言处理 前端开发
详谈JavaScript 二进制家族:Blob、File、FileReader、ArrayBuffer、Base64
详谈JavaScript 二进制家族:Blob、File、FileReader、ArrayBuffer、Base64
89 1
|
1月前
|
开发框架 JavaScript 小程序
uniapp、vue、小程序、js图片转base64 示例代码
uniapp、vue、小程序、js图片转base64 示例代码
|
1月前
|
JavaScript 前端开发
js的input标签上传图片并转为base64预览
js的input标签上传图片并转为base64预览
65 0
|
Web App开发 JavaScript 前端开发
|
JavaScript 算法 前端开发