Skip to content
imshengli blog
Go back

HTML5 Blob:二进制操作、文件下载与分片上传

Blob 对象详解:构造函数、Blob URL、与 File 的关系,实战文件下载、图片预览和分片上传。

· 4 min

背景

本文主要总结HTML5中,关于Blob对象的相关知识。 Blob:Binary Large Object。

为什么要有Blob对象?

文件和二进制数据的操作中, 讲JavaScript无法直接处理二进制数据, 而ECMAScript 5引入了Blob对象,允许直接操作二进制数据。

什么是Blob对象?

Blob对象,是一个代表着二进制数据的基本对象。

创建Blob对象:

Blob对象,有两个只读属性:

Blob 构造函数

Blob 构造函数接收两个参数:数据数组和配置对象。

// 从字符串创建
var textBlob = new Blob(['Hello, World!'], { type: 'text/plain' });
console.log(textBlob.size); // 13
console.log(textBlob.type); // "text/plain"

// 从多段数据创建
var htmlBlob = new Blob(['<h1>', 'Title', '</h1>'], { type: 'text/html' });

// 从 JSON 创建
var data = { name: 'test', value: 123 };
var jsonBlob = new Blob([JSON.stringify(data)], { type: 'application/json' });

slice 方法

slice 用于截取 Blob 的一部分,返回新的 Blob 对象:

var blob = new Blob(['Hello, World!'], { type: 'text/plain' });
var partial = blob.slice(0, 5, 'text/plain');
console.log(partial.size); // 5

var reader = new FileReader();
reader.onload = function () {
  console.log(reader.result); // "Hello"
};
reader.readAsText(partial);

Blob URL

通过 URL.createObjectURL() 为 Blob 生成临时 URL,可用于 DOM 元素的 src 或 href 属性:

var blob = new Blob(['body { color: red; }'], { type: 'text/css' });
var url = URL.createObjectURL(blob);
// "blob:http://localhost/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

// 使用完毕后释放内存
URL.revokeObjectURL(url);

特点:只在当前会话有效,每次调用生成新引用,需手动释放。

Blob 与 File 的关系

File 继承自 Blob,额外增加了 name、lastModified 等文件属性:

// 通过 input 获取 File
document.getElementById('fileInput').addEventListener('change', function (e) {
  var file = e.target.files[0];
  console.log(file.name);         // 文件名(File 特有)
  console.log(file.size);         // 继承自 Blob
  console.log(file.type);         // 继承自 Blob
  console.log(file.lastModified); // File 特有

  // File 可以使用 Blob 的 slice 方法
  var chunk = file.slice(0, 1024);
});

// 手动构造 File
var file = new File(['content'], 'test.txt', { type: 'text/plain' });

实际应用

文件下载

前端生成文件并触发下载:

function download(content, filename, type) {
  var blob = new Blob([content], { type: type || 'text/plain' });
  var url = URL.createObjectURL(blob);
  var a = document.createElement('a');
  a.href = url;
  a.download = filename;
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
  URL.revokeObjectURL(url);
}

download('Hello!', 'hello.txt', 'text/plain');
download(JSON.stringify({ a: 1 }, null, 2), 'data.json', 'application/json');

图片预览

选择图片后本地预览,无需上传:

document.getElementById('imageInput').addEventListener('change', function (e) {
  var file = e.target.files[0];
  if (!file.type.startsWith('image/')) return;

  var url = URL.createObjectURL(file);
  var img = document.getElementById('preview');
  img.src = url;
  img.onload = function () {
    URL.revokeObjectURL(url);
  };
});

分片上传

大文件利用 slice 切片后逐片上传:

function uploadByChunks(file, chunkSize) {
  chunkSize = chunkSize || 2 * 1024 * 1024; // 2MB
  var totalChunks = Math.ceil(file.size / chunkSize);
  var current = 0;

  function next() {
    if (current >= totalChunks) { console.log('完成'); return; }
    var start = current * chunkSize;
    var chunk = file.slice(start, start + chunkSize);

    var formData = new FormData();
    formData.append('file', chunk);
    formData.append('chunk', current);
    formData.append('total', totalChunks);
    formData.append('filename', file.name);

    var xhr = new XMLHttpRequest();
    xhr.open('POST', '/upload/chunk');
    xhr.onload = function () {
      current++;
      console.log(Math.round(current / totalChunks * 100) + '%');
      next();
    };
    xhr.send(formData);
  }
  next();
}

扩展阅读

在Blob的基础上,又衍生出一系列相关的API,用来操作文件。

参考链接


Share this post on:

Previous Post
ES6 Generator:yield、惰性求值与异步控制
Next Post
JavaScript Object:创建方式、原型链与深浅拷贝