到目前,本系列文章集中讲了File对象能在用户参与下对操作文件的产生的积极效果。事实上File对象是Blob的特殊类型。即大块的二进制数据,File对象的尺寸及类型等属性都继承自Blob。

大多时候, Blob 的 File是可以同时使用的。例如,可以用FileReader从Blob中读取数据,可以通过URL.createObjectURL()来创建一个URL对象。

拆分

一个有趣的功能就是你能基于一个Blob创建另一个全新Bolb(File也一样)。这是由于每个Blob 都是指向数据而不是数据本身,你可以轻易的从一个Blob创建另一个指向其的Blob对象,就是使用slice()方法。

你对string和array的 slice()方法肯定不陌生,Blob 的slice()功能也近似。这方法接收三个参数:开始字节位置,结果字节位置,MIME type[可选]。如果不指定MIME type 则与原生的相同。

支持slice() 的浏览器目前不多,Firefox支持 mozSlice() ,chrome支持webkitSlice()

function sliceBlob(blob, start, end, type) {

    type = type || blob.type;

    if (blob.mozSlice) {
        return blob.mozSlice(start, end, type);
    } else if (blob.webkitSlice) {
        return blob.webkitSlice(start, end type);
    } else {
        throw new Error("This doesn't work!");
    }
}

也可以使用这个封装好的方法,例如,将一个较大的文件拆分后再上传。每个Blob都是自原先的对象独立生成,每个可存在重复数据。Flickr 的工程师通过blob 读取图片上传到服务器过程中的Exif 信息而不是上传完后再读。文件一选中Flickr就边上传边读取图片的Exif 信息。他们就可以在图片上传的过程中将图片的信息在页面上预先显示出来了。

通过老办法创建Blob

File 对象在浏览器上出现后不久,开发者就意识到Blob对象更加强大都急于希望能不通过用户参与就创建之。毕竟,任何数据都能用Blob描述,而且无需被关联上某个文件。浏览器创建 BlobBuilder的效率很高,即一个可将数据包装进Blob对象的类型。这是个非标准类型,Firefox 对应有 MozBlobBuilder,Internet Explorer 10 对应有asMSBlobBuilder), Chrome 对应有WebKitBlobBuilder。

BlobBuilder 功能是通过对象的append()方法添加string,ArrayBuffer, 或者 Blob类型的数据,然后通过 getBlob() 方法传入对应的 MIME type 就能得到一个Blob对象了:

var builder = new BlobBuilder();
builder.append("Hello world!");
var blob = builder.getBlob("text/plain");

这种通过任意数据类型创建URL对象太强大了,允许你动态的创建能被浏览器识别成文件的对象。没错,再如,通过Blob在没有对应文件(地址)的情况下创建一个web worker。 这个技术在 The Basics of Web Workers[2]:

// Prefixed in Webkit, Chrome 12, and FF6: window.WebKitBlobBuilder, window.MozBlobBuilder
var bb = new BlobBuilder();
bb.append("onmessage = function(e) { postMessage('msg from worker'); }");

// Obtain a blob URL reference to our worker 'file'.
// Note: window.webkitURL.createObjectURL() in Chrome 10+.
var blobURL = window.URL.createObjectURL(bb.getBlob());

var worker = new Worker(blobURL);
worker.onmessage = function(e) {
  // e.data == 'msg from worker'
};
worker.postMessage(); // Start the worker.

上例先编写了几行代码然后创建了一个URL对象,对象被用于替代外链脚本来创建一个web worker。

你可以任意无限的调用 append() 来创建类型为Blob的内容。

通过新办法来创建Blob

因为开发都们都强烈要求直接创建Blob对象,且浏览器有了BlobBuilder,它打算追加一个Blob 构造方法,些构造方法是新的规范,将是今后创建Blob对象的方法。

此构造方法接收两个参数,第一个是个将合成 Blob对象的数据数组。作用跟 BlobBuilder的append() 方法相同,类型可为 任意的strings,Blobs, 和 ArrayBuffers。第二个参数是含有属性的将生成的新Blob的对象,这个对象的属性通常有两个:type, 即 MIME type;endings, 值可为 “transparent” (默认) 或者 “native”。例:

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

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

显然,这要比使用 BlobBuilder简单得多。

Blob 的构造方法在nightly builds 版的Chrome 和Firefox 13中支持了。 其他浏览器还没有相关消息。无论怎样,这已经是  File API[3]标准的一部分了所以肯定将会得到普遍支持的。

总结

这是JavaScript操作文件系列文章的最后一篇了。我希望你有所收获,File API 无比的强大在web应用中开创了一个全部的方式来处理文件。当用户要上传文件时你再也无需无奈的使用上传组件了。而且你可以直接在客户端读取文件,完全开放了客户端各种文件操作能力。你可以裁剪一张过大的图片再上传 (用FileReader 和 <canvas>);你可以在性能差的浏览中换成文本编辑器,你可以将较大的文件拆分成小块再上传,还有很多可能,不过都大致相同。

参考

  1. Parsing Exif client-side using JavaScript by Flickr Team
  2. The Basics of Web Workers by Eric Bidelman
  3. File API – Blob Constructor

Disclaimer: Any viewpoints and opinions expressed in this article are those of Nicholas C. Zakas and do not, in any way, reflect those of my employer, my colleagues, Wrox PublishingO’Reilly Publishing, or anyone else. I speak only for myself, not for them.

原文