「JavaScript深入」二进制数据处理详解「Blob、File、FileReader、ArrayBuffer、Typed Arrays、DataView」
JavaScript 主要用于处理文本数据,但在更复杂的应用(如图像、音频、视频处理)中,二进制数据的操作变得尤为重要。是一种用于表示通用、固定长度的原始二进制数据缓冲区,它是处理二进制数据的基础,可以用于存储各种类型的数据,必须通过。在 JavaScript 中都是用于处理二进制数据的对象,在部分场景两者都能胜任,但擅长的场景有所区别。Blob 代表不可变的二进制数据块,通常用于处理文件、图像、
二进制数据处理详解
JavaScript 主要用于处理文本数据,但在更复杂的应用(如图像、音频、视频处理)中,二进制数据的操作变得尤为重要。下面将深入探讨 JavaScript 提供的二进制数据操作 API
- Blob:用于代表不可变的二进制数据(如文件)
- File:继承自 Blob,代表用户从文件系统选择的具体文件
- FileReader:用于读取 File 或 Blob 对象的内容
- ArrayBuffer:代表通用、固定长度的原始二进制数据缓冲区
- Typed Arrays:提供了一种操作 ArrayBuffer 中数据的方式,支持多种数据类型(如 Uint8Array、Float32Array 等)
- DataView:允许以任意字节顺序(endianness)读取和写入 ArrayBuffer 中的数据
1. Blob(Binary Large Object)
Blob 代表不可变的二进制数据块,通常用于处理文件、图像、音频等类型的数据。
Blob 的特性
- 支持二进制数据:可存储文本、图像、音频等数据。
- 不可变性:创建后 Blob 数据不能被修改。
- 分块存储:可使用
slice()方法将 Blob 拆分为多个小块。
创建 Blob
// 从字符串创建 Blob
const text = "Hello, Blob!";
// 为 Blob 指定正确的 MIME 类型,确保数据在使用时被正确解析和处理
const blob = new Blob([text], { type: 'text/plain' });
console.log(blob.size); // 12
console.log(blob.type); // 'text/plain'
// 从二进制数据创建 Blob
const bytes = new Uint8Array([0x48, 0x65, 0x6C, 0x6C, 0x6F]); // 'Hello'
const binaryBlob = new Blob([bytes], { type: 'application/octet-stream' });
console.log(binaryBlob.size); // 5
console.log(binaryBlob.type); // 'application/octet-stream'
Blob 主要方法
slice(start, end, contentType): 截取 Blob 的部分数据,生成新的 Blob 片段。arrayBuffer(): 将 Blob 转换为ArrayBuffer,适用于二进制数据操作。text(): 将 Blob 转换为字符串,适用于文本数据读取。stream(): 将 Blob 转换为字符串,适用于文本数据读取。
Blob 的应用
👇 Blob 对象常用于处理文件上传和下载。例如通过 Blob 可以创建一个包含特定数据的文件,然后通过 URL.createObjectURL 将其转换为下载链接
const data = "Sample data for download";
const blob = new Blob([data], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = 'sample.txt';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
👇 Blob 也经常用于处理和操作图像数据,例如将 Canvas 内容转换为图像 Blob,然后显示
const canvas = document.getElementById('myCanvas');
canvas.toBlob((blob) => {
const url = URL.createObjectURL(blob);
const img = document.createElement('img');
img.src = url;
document.body.appendChild(img);
}, 'image/png');
在不需要时使用
URL.revokeObjectURL()释放对象 URL,防止内存泄漏
👇 在进行网络通信时,Blob 可以作为数据传输的容器,尤其是在使用 fetch API 时传输二进制数据
fetch('https://example.com/api/upload', {
method: 'POST',
body: blob,
headers: {
'Content-Type': 'text/plain'
}
}).then(response => {
return response.json();
}).then(data => {
console.log(data);
});
2. File
File 继承自 Blob,表示来自用户文件系统的文件,并包含额外的元数据(如文件名、大小和类型)。
File 对象的属性
| 属性 | 描述 |
|---|---|
name |
文件名称,包含扩展名 |
size |
文件大小(字节) |
type |
MIME 类型 |
lastModified |
最后修改时间(时间戳) |
lastModifiedDate |
lastModified 的 Date对象 |
webkitRelativePath |
用户选择文件时的相对路径 |
获取 File 对象
最常见的 File 对象创建方式是通过用户在网页中上传文件。这通常通过 元素或拖放操作实现
<input type="file" id="fileInput">
<script>
const fileInput = document.getElementById('fileInput');
fileInput.addEventListener('change', (event) => {
const file = event.target.files[0];
console.log(`文件名: ${file.name}, 文件大小: ${file.size} 字节`);
});
</script>
3. FileReader
FileReader 允许异步读取 File 或 Blob 内容,支持文本、Data URL 和 ArrayBuffer 读取。
创建 FileReader
FileReader 对象可以通过调用其构造函数直接创建
const reader = new FileReader();
使用 FileReader.abort() 方法可以取消正在进行的读取操作
主要方法
readAsArrayBuffer(blob): 读取 Blob 并返回ArrayBuffer。readAsDataURL(blob): 读取 Blob 并返回 data URL(base64 编码的字符串)。readAsText(blob, encoding): 读取 Blob 并返回文本字符串。
主要事件
当调用上述方法后会触发 FileReader 的事件
| 事件 | 描述 |
|---|---|
onloadstart |
开始读取操作时触发 |
onprogress |
onprogress 读取过程中定期触发,可用于显示进度 |
onabort |
读取操作被中止时触发 |
onerror |
读取过程中发生错误时触发 |
onload |
读取操作成功完成时触发 |
onloadend |
读取操作完成(无论成功或失败)时触发 |
文件上传与读取内容示例
👇 在用户上传文件后,使用 FileReader 可以提前读取文件内容,进行预览、验证或处理。
<!DOCTYPE html>
<html>
<head>
<title>读取文本文件示例</title>
</head>
<body>
<input type="file" id="textFileInput" accept=".txt, .md" />
<pre id="fileContent"></pre>
<script>
const textFileInput = document.getElementById('textFileInput');
const fileContent = document.getElementById('fileContent');
textFileInput.addEventListener('change', (event) => {
const file = event.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = (e) => {
fileContent.textContent = e.target.result;
};
reader.onerror = () => {
fileContent.textContent = '读取文件时发生错误。';
};
reader.readAsText(file);
} else {
fileContent.textContent = '未选择任何文件。';
}
});
</script>
</body>
</html>
👇 使用 readAsDataURL 方法,可以将用户上传的图像文件转换为可以直接在网页中显示的 URL
<!DOCTYPE html>
<html>
<head>
<title>图像预览示例</title>
</head>
<body>
<input type="file" id="imageInput" accept="image/*" />
<img id="imagePreview" src="" alt="图像预览" style="max-width: 300px;" />
<script>
const imageInput = document.getElementById('imageInput');
const imagePreview = document.getElementById('imagePreview');
imageInput.addEventListener('change', (event) => {
const file = event.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = (e) => {
imagePreview.src = e.target.result;
};
reader.onerror = () => {
console.error('读取图像文件时发生错误。');
};
reader.readAsDataURL(file);
} else {
imagePreview.src = '';
}
});
</script>
</body>
</html>
文件分块读取示例
对于非常大的文件,可以利用 Blob.slice 方法分块读取,避免占用过多内存。
const chunkSize = 1024 * 1024; // 1MB
let offset = 0;
function readChunk(file) {
if (offset >= file.size) return;
const slice = file.slice(offset, offset + chunkSize);
const reader = new FileReader();
reader.onload = (event) => {
const text = event.target.result;
console.log(`读取第 ${offset / chunkSize + 1} 块:`, text);
offset += chunkSize;
readChunk(file);
};
reader.onerror = () => {
console.error('读取块时发生错误。');
};
reader.readAsText(slice);
}
readChunk(file);
4. ArrayBuffer 与 Typed Arrays、DataView
ArrayBuffer
ArrayBuffer 是一种用于表示通用、固定长度的原始二进制数据缓冲区,它是处理二进制数据的基础,可以用于存储各种类型的数据,必须通过 Typed Arrays 或 DataView 访问。
ArrayBuffer 使用领域
- 网络通信: WebSockets 和 Fetch API: 在与服务器进行低级网络通信时,
ArrayBuffer可以用于发送和接收二进制数据 - 科学计算和数据分析: 在需要高效率大量数据运算的应用中(如图像处理、音频处理、科学计算),
ArrayBuffer配合TypedArray可实现更高效的数据处理 - 图像处理: 可以在
Canvas元素中使用ArrayBuffer来高效处理图像数据 - 大数据处理:
ArrayBuffer提供了对内存中二进制数据的直接访问权限,这在处理大数据集时尤其有用
// 创建一个 8 字节的 ArrayBuffer
const buffer = new ArrayBuffer(8);
console.log(buffer.byteLength); // 输出: 8
ArrayBuffer 本身不能直接读取或写入数据,必须通过 Typed Arrays 或 DataView 对象来操作 👇👇👇
Typed Arrays
TypedArray 提供了一种操作 ArrayBuffer 中数据的方式,允许以特定的字节序和数据类型读写二进制数据
👇 JavaScript 提供了多种类型的 TypedArray ,每种对应不同的数据类型和字节长度,它们为不同的数据类型(如整数、浮点数)提供了高效的操作接口
| 类型 | 描述 | 字节长度 |
|---|---|---|
Int8Array |
8 位有符号整数 | 1 |
Uint8Array |
8 位无符号整数 | 1 |
Uint8ClampedArray |
8 位无符号整数,值被夹断到 [0, 255] | 1 |
Int16Array |
16 位有符号整数 | 2 |
Uint16Array |
16 位无符号整数 | 2 |
Int32Array |
32 位有符号整数 | 4 |
Uint32Array |
32 位无符号整数 | 4 |
Float32Array |
32 位浮点数 | 4 |
Float64Array |
64 位浮点数 | 8 |
BigInt64Array |
64 位有符号大整数(ES2020 引入) | 8 |
BigUint64Array |
64 位无符号大整数(ES2020 引入) | 8 |
创建 Typed Arrays
Typed Arrays 特别适用于科学计算、图像处理、音频处理等需要高性能的数据操作场景
// 16 字节的缓冲区
const buffer = new ArrayBuffer(16);
// 创建一个 Float32Array 视图
const floatView = new Float32Array(buffer);
floatView[0] = 3.14;
floatView[1] = 2.718;
console.log(floatView); // 输出: Float32Array [ 3.14, 2.718, 0, 0 ]
DataView
DataView 提供了一种更灵活的方式来操作 ArrayBuffer 中的数据,允许以任意的字节序(大端或小端)读写不同类型的数据。
相比 Typed Arrays,DataView 更加通用,适用于需要处理复杂数据结构的场景
DataView 示例
const buffer = new ArrayBuffer(16); // 16 字节的缓冲区
const dataView = new DataView(buffer);
// 设置不同类型的数据
dataView.setInt8(0, 127); // 第一个字节设置为有符号 8 位整数
dataView.setUint16(1, 65000, true); // 从第 1 个字节开始,设置无符号 16 位整数,字节序为小端
dataView.setFloat32(3, 3.14, false); // 从第 3 个字节开始,设置 32 位浮点数,字节序为大端
// 读取数据
console.log(dataView.getInt8(0)); // 输出: 127
console.log(dataView.getUint16(1, true)); // 输出: 65000
console.log(dataView.getFloat32(3, false)); // 输出: 3.140000104904175
Typed Arrays 和 DateView 选择
- 如果需要处理同一类型的数据,且不需要控制字节序,使用
Typed Arrays更为方便和高效 - 如果需要处理复杂的数据结构,或需要在数据中混合多种类型,且需要控制字节序,使用
DataView更为合适
5. ArrayBuffer vs Blob
ArrayBuffer 和 Blob 在 JavaScript 中都是用于处理二进制数据的对象,在部分场景两者都能胜任,但擅长的场景有所区别
| 特性 | ArrayBuffer | Blob |
|---|---|---|
| 可变性 | 可变 | 不可变 |
| 读取方式 | 需要 TypedArray 或 DataView | 直接使用 FileReader |
| 适用场景 | 计算、数据分析、网络通信 | 文件处理、存储、传输 |
6. 图像颜色反转示例
假设我们从服务器获取了一张灰度图像的二进制数据,我们需要对其进行处理,比如反转颜色。
// 模拟从服务器获取的图像数组(二进制数据)
function fetchImageData() {
// 假设我们有一个 2x2 的灰度图像示例数据(4 个像素,每个像素 8 位灰度值)
return new Uint8Array([100, 150, 200, 250]); // 灰度值
}
function processImageData() {
// 获取图像数据
let imageData = fetchImageData();
// 创建一个 ArrayBuffer,长度与 imageData 相同
let buffer = new ArrayBuffer(imageData.length);
// 创建一个视图来操作这个缓冲区
let view = new Uint8Array(buffer);
// 复制数据到缓冲区
for (let i = 0; i < imageData.length; i++) {
view[i] = imageData[i];
}
// 处理图像数据(颜色反转)
for (let i = 0; i < view.length; i++) {
view[i] = 255 - view[i]; // 反转灰度值
}
// 输出处理后的数据
console.log('Processed Image Data:', view);
}
processImageData();
结论
JavaScript 提供了一系列强大的二进制数据处理 API,能够高效地处理文件、图像、音频等数据。掌握它们能大幅提升 Web 应用的能力,满足更复杂的数据处理需求。
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐

所有评论(0)