Zerlinda's Blog

你不知道的Blob和FileReader

一、需要了解的一些基本的常识

BLOB (binary large object),二进制大对象,是一个可以存储二进制文件的容器。

BLOB是一个大文件,典型的BLOB是一张图片或一个声音文件,由于它们的尺寸,必须使用特殊的方式来处理(例如:上传、下载或者存放到一个数据库)。

在JavaScript中,Blob 对象表示一个不可变、原始数据的类文件对象。Blob 表示的不一定是JavaScript原生格式的数据。File接口基于Blob,继承了 blob 的功能并将其扩展使其支持用户系统上的文件。

首先,通过一个简单的Demo来看一下BLOB能做些什么?

具体源代码网页请点击这里

以上使用blob和FileReader提供的一些基本的api就可以实现,具体来说实现的功能是图片预览。通过URL.createObjectURL创建指向Blob或者File的url。究竟什么是Blob呢?

Blob代表原始二进制数据,通过Blob对象的slice()方法,可以访问里面的字节数据。Blob接口还有两个属性:size和type。

属性

Blob.size:只读,表示Blob 对象中所包含数据的大小(字节)。

Blob.type:只读,一个字符串,表明该Blob对象所包含数据的MIME类型。如果类型未知,则该值为空字符串。

方法

slice()方法原本接受length作为第二个参数,以表示复制到新Blob对象的字节数。如果设置的参数使start + length超出了源Blob对象的大小,那返回的则是从start到结尾的数据。

构造函数

	Blob(blobParts[, options])

返回一个新创建的 Blob 对象,其内容由参数中给定的数组串联组成。

创建Blob对象

生成Blob对象有两种方法:一种是使用Blob构造函数,另一种是对现有的Blob对象使用slice方法切出一部分。

1).Blob 构造函数用法

var debug = {hello: "world"};  
var blob = new Blob([JSON.stringify(debug, null, 2)], {type :'application/json'});

2).Blob.slice()用法

var newBlob = blob.slice(1)

Blob衍生对象

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

    ● File:负责处理那些以文件形式存在的二进制数据,也就是操作本地文件;

    ● FileList:File对象的网页表单接口;  

    ● FileReader:负责将二进制数据读入内存内容;

    ● URL:用于对二进制数据生成URL。

简单介绍下这几个对象:

1.File对象

File 对象是特殊类型的 Blob,且可以用在任意的 Blob 类型的 context 中。 FileReader, URL.createObjectURL(), createImageBitmap(), 及 XMLHttpRequest.send() 都能处理 Blob 和 File。

File对象的主要属性值如下。

● name:文件名,该属性只读。

● size:文件大小,单位为字节,该属性只读。

● type:文件的MIME类型,如果分辨不出类型,则为空字符串,该属性只读。

2、FileList

一个FileList对象通常来自于一个HTML input元素的files属性,当设置mutiple多选时你可以通过这个对象访问到用户所选择的文件.该类型的对象还有可能来自用户的拖放操作,查看DataTransfer对象了解详情.

当然你可以通过.item()或者根据给定的索引值.返回FileList对象中对应的File对象.

3、URL

URL 接口是一个包含若干静态方法的对象,用来创建 URLs。当使用一个没有实现该构造器的用户代理时,可以通过 Window.URL 属性来访问该对象。

方法:

URL.createObjectURL():返回一个DOMString ,包含一个唯一的blob链接(该链接协议为以blob:,后跟唯一标识浏览器中的对象的掩码)。使用时如objectURL = URL.createObjectURL(blob);

URL.revokeObjectURL():销毁之前使用URL.createObjectURL()方法创建的URL实例。

4、FileReader

FileReader用于Web应用程序异步读取存储在用户计算机上的文件。通过使用构造函数new FileReader(blob/file)创建FileReader对象

方法:

abort():中止读取操作。在返回时,readyState属性为DONE。

readAsArrayBuffer():开始读取指定的 Blob中的内容, 一旦完成, result 属性中保存的将是被读取文件的 ArrayBuffer 数据对象.

readAsBinaryString():result属性中将包含所读取文件的原始二进制数据。

readAsDataURL():result属性中将包含一个data: URL格式的字符串以表示所读取文件的内容。

readAsText():result属性中将包含一个字符串以表示所读取的文件内容。

事件处理

onabort:处理abort事件。该事件在读取操作被中断时触发。

onerror:处理error事件。该事件在读取操作发生错误时触发。

onload:处理load事件。该事件在读取操作完成时触发。

onloadstart:处理loadstart事件。该事件在读取操作开始时触发。

onloadend:处理loadend事件。该事件在读取操作结束时(要么成功,要么失败)触发。

onprogress:处理progress事件。该事件在读取Blob时触发。

在事件处理程序中最重要的是onload方法,通过读取this.result可以获得读取的文件内容。fileReader是读取Blob的唯一方法,调用不同的api决定不同的返回类型。readAsDataURL通常可以将文件读取为一个链接,readAsText可以将文件读取为一段文本,readAsBinaryString可以读取为一段二进制实现分片上传等。readAsArrayBuffer涉及到的api比较多,看下面一个例子具体了解一下。

二、通过FileReader读取Blob内容

从Blob中读取内容的唯一方法是使用 FileReader。上面已经讲过FileReaderAPI,我们直接来实现一段代码体验一下。

假设某特定二进制文件,我们需要从中读取一段内容的值。具体来说,文件的第一字节表示一个length,从第二字节到第length-1字节的内容正是我们要读取的内容。那么如何读取这段信息呢?

var r = new FileReader();
r.readAsArrayBuffer(file);
r.onload = function (e) {
  let buffer = this.result,
    datav = new DataView(buffer),
    len = datav.getUint8(0),
    nameBuffer = buffer.slice(0, 0 + len),
    name = String.fromCharCode.apply(null, new Uint8Array(nameBuffer));
}

按字节读取毫无疑问是使用FileReader的readAsArrayBuffer方法。那么fromCharCode,DataView,getUint8和Uint8Array又是干啥的?

ArrayBuffer 对象用来表示通用的、固定长度的原始二进制数据缓冲区。ArrayBuffer 不能直接操作,而是要通过类型数组对象DataView 对象来操作,它们会将缓冲区中的数据表示为特定的格式,并通过这些格式来读写缓冲区的内容。

类型数组对象(TypedArray)

类型数组对象(TypedArray)描述一个底层的二进制数据缓存区的一个类数组视图。基本可以理解为一个数组,因为数组的方法它都有,但会具备一些特殊的属性和方法,比如表示字节长度的byteleng等。TypedArray有许多不同的全局对象,包括Int8Array(),Uint8Array()等。下面的例子设置和使用标准数组语法创建一个TypedArray:

var buffer = new ArrayBuffer(8);
var view   = new Int32Array(buffer);
console.log(view.length) //2     8*8/32 =2

下面的例子创建了一个 8 字节的缓冲区,并使用一个 Int32Array 来引用它:

var buffer = new ArrayBuffer(8);
var view   = new Int32Array(buffer);
console.log(view.length) //2     8*8/32 =2

DataView 视图

DataView 视图是一个可以从 ArrayBuffer 对象中读写多种数值类型的底层接口,在读写时不用考虑平台字节序问题。它跟typeArray一样,有私有的getInt8(),getUint8()等方法。

下面的例子创建了一个 8 字节的缓冲区,读取第二个字节的内容。

var buffer = new ArrayBuffer(8);
var dataview = new DataView(buffer);
dataview.getInt8(1); // 0

getInt8()方法从DataView起始位置以byte为计数的指定偏移量(byteOffset)处获取一个有符号的8-bit整数(一个字节);

最后,String.fromCharCode()方法返回使用指定的Unicode值序列创建的字符串。所以上面的例子就不难解读了。

评论(1)

发表评论

电子邮件地址不会被公开。 必填项已用*标注