未来Web应用开发探秘:File API
我们不止一次的提到File API以及Web应用程序对本地资源的访问,比如《JavaScript将增加本地操作API 可直接操作本地文件》和《HTML5 File API初探支持文件拖放上传功能》等。这不只是一个功能或者API,它还代表了未来Web应用开发的一个趋势。
回想一下过去那些糟糕的日子:要上传文件到一个网站需要在一个file input上点击“浏览”按钮,然后导航到这个文件所在的文件夹,再点击“打开”,如果要上传多个文件,需要对每一个文件重复上面的步骤!有了File API,那些日子将一去不复返了。
File API是什么?
File API是一套强大的API,它可以让开发者处理来自于用户文件系统的文件,并且可以让开发者在Web应用程序里使用这些文件,所有这些事情都在本地处理,不需要在服务器上处理。
File API能做什么?
在很多场景下,许多应用程序中,File API都是很有用的。最明显的用途就是使用Drag和Drop API在drop事件上访问文件的,来支持拖放式上传文件(比如image)。当用户drop文件的时候,你可以把他们转换成一个data URL,马上给用户提供反馈,同时可以用异步的方式把要上传的image的缩略图展示给用户,这可以给用户提供一个无缝的交互体验。
几个例子:
我们收集了一个炫耀File API的例子(http://www.thecssninja.com/demo/crystalball/),这个Demo可以在Firefox3.6和Chrome 6 dev版上正常运行。从你的桌面上拖放任意文件到这个Demo中,看看会发生什么......
◆一个图片编辑器——http://demos.hacks.mozilla.org/openweb/imageUploader
◆box.net最近添加了对拖放式上传文件的支持—— box.net
◆font dragr –测试自定义字体的Web应用程序*– http://fontdragr.com
如何使用File API
使用File API,你有两种方法可以访问一个文件并进行操作。第一种方法是通过file input和文件属性。
# document.getElementById("fileinput").files
上面的代码访问了FileList对象,它是一个包含多个文件的序列数组。每个文件都有几个属性可用,例如name, size和type
访问一个文件的另一种方法是通过Drag和Drop API,在dataTransfer对象上,也包含一个FileList对象,dataTransfer对象在DnD API的drop事件上可用。
event.dataTransfer.files
这两种方法都返回同一个序列数组。拖放多个文件可以被处理,并且如果file input有multiple属性,它也可以处理多个文件。
FileReader
为了用FileList对象来做一些事情,在无需服务器参与的情况下操作文件来显示给用户,我们可以使用FileReader对象。它是异步处理的,所以只要不锁定浏览器的UI,它就一直在处理文件。
var reader = new FileReader();
reader.onload = function (evt) {
// do something with the file once it's loaded
var data = evt.target.result, // file is stored in the result attribute;
img = document.createElement("img");
img.src = data;
document.getElementsByTagName("body").appendChild(img);
}
reader.readAsDataURL(file);
上面的代码我们创建了一个新的FileReader对象,然后我们初始化了我们的onload函数,所以只要文件载入了内存,我们就可以操作这个文件了。最后一个函数告诉reader,我们想用这个文件做什么。在我们的实例中,是返回一个DataURL。还有两个其他的方法可以使用,它们是:
readAsText()和readAsBinary()
在onload事件的内部,我们创建了一个新的image元素,设置它的source设置成result属性的值,然后把它附加到document body上。这立刻会把这个image显示给用户。
处理大文件——File URL
在前面的例子里,我已经向你展示了如何载入一个文件,然后把它展示给用户。所有这些方法本质上都是用readAsDataURL/Binary/Text等函数创建一个文件的拷贝,然后把它载入你的可用内存中。当用户载入了许多文件,或非常大的文件的时候,就会产生问题。比如说,用户要拖动一个200MB的视频或者它们拖入了许多的视频!这将会产生大量的数据,它们都需要载入内存,这会使任何机器突然停止响应,更可能的结果是使浏览器崩溃。值得庆幸的是File API的创建者和贡献者已经想到了这个问题,并且在FileReader对象上添加了一个非常有用的属性——url。
URL
URL是一个随机产生的唯一字符串,它映射到你的硬盘上的一个物理文件。这是很有用的,因为这个唯一的字符串可以在html文档中使用。例如有一个image。把这个image的source设置成File API生成的唯一字符串,不需要把它载入内存,就可以让你把这个image显示给用户。
# <img src="moz-filedata:8616e48b-2a2b-418d-9ad4-5669858cf038" />
上面的例子展示了在Firefox 4中使用的url属性,image的source应该是什么样子的。
想象一下这个场景。在你的图片网站上,你有一个image uploader,用户在他们的图片里拖动了一些文件,要drop的那些图片显示成了一个漂亮的缩小版本的网格,但是用户发现了一个问题,认识到那些image中,有一个需要修整一下。他们在一个图片编辑器中打开这个文件,做了一些修整,回到Web应用程序并点击上传按钮。使用url的好处是改变的文件也可以被上传,因为它实时的链接到文件系统中的物理image,所以无须用户重新把它们添加到上传列表中。
到现在为止,Firefox 4是唯一一个支持url属性的浏览器,即便如此,它还存在一个bug:唯一字符串只能显示通过file input载入的image。无法显示通过drop事件载入的image。但是,在Firefox 4的稳定版本中,这个bug应该已经被修复了。
看看这个Firefox 4中的Demo(http://www.thecssninja.com/demo/crystalball/fileurl.html),它使用一个file input载入文件,使用了url属性。
1. // Code showing url
2. var droppedFileURL = file.url;
3. ...
4. img.src = droppedFileURL;
上面的代码很简单。并不需要附加一个事件来把image载入内存,然后把它转换成一个data URL,我们只需要简单的遍历文件,访问file对象的url属性,然后用它设置我们的image的source。对于开发者来说,工作量减轻了,同时用户计算机的压力也减轻了。这是一个两全其美的方法。
向何处前进
在写这篇文章的时候,只有两个浏览器支持File API:Firefox 3.6和Chrome 6,它们分别在不同程度上支持了File API规范。
File API只是许多正在使用的一线API中的一种。例如,FileWriter和Media Interface(Web摄像头访问)在一起使用将爆发出惊人的潜力。这只是未来的开始,离“在桌面的世界里让Web应用程序成为一等公民”这个目标,我们又近了一步。这条线变得更加模糊了。