File API的宗旨是为Web开发人员提供一种安全的方式,以便在客户端访问用户计算机中的文件,并更好地对这些文件执行操作。

HTML5虽然可以让我们访问本地文件系统,但是文件只有在用户触发了文件读取行为才能读取到File API,这通常在发生在表单文件选择和拖拽的情况下。

一. File API的兼容性

File API在各大主流浏览器中的支持情况如下图所示:

image_1aq4834d3116gcos1gkh156b19m19.png-43kB

备注:图片转载自: http://www.ibm.com/developerworks/cn/web/1210_jiangjj_html5log/

浏览器对 File API 支持情况的更详细信息可以参考网站 http://caniuse.com/#search=File

可以用下面的方法检测当前浏览器是否支持File API:

function checkSupportFileAPI() {
    if(window.File && window.FileList && window.FileReader) {
        return true;
    } else {
        return false;
    }
}

二. File对象的属性

FileAPI在表单中的文件输入字段的基础上,又添加了一些直接访问文件信息的接口。HTML5在DOM中为文件输入元素添加了一个file集合。在通过文件输入字段选择了一或多个文件时,files集合中将包含一组File对象,每个File对象对应着一个文件。每个File对象都有下列只读属性:

  • name: 本地文件系统的文件名;
  • size:文件的字节大小;
  • type:String类型,文件的MIME类型;
  • lastModifiedDate:String类型,文件最后被修改的时间。

在HTML5中,通过添加multiple属性,file控件内允许一次放置多个文件。控件内的每一个选择的文件都是一个file对象。

例子:通过监听change事件,并读取files集合就可以知道每个文件的信息:

<input type="file" name="" id="filesList" multiple>

<script type="text/javascript">
    var filesList = document.getElementById("filesList");
    filesList.addEventListener("change", function(e) {
        var files = this.files,
            i = 0,
            len = 0;
        if(files) {
            len = files.length;
        }
        while(i < len) {
            console.log(files[i].name + "( " + files[i].type + ", " + files[i].size + "bytes )");
            i++;
        }
    });
</script>

选择三个文件后,console中输出如下:

a.jpg( image/jpeg, 1499704bytes )
b.png( image/png, 395511bytes )
c.jpg( image/jpeg, 1614001bytes )

三. FileReader对象

3.1 FileReader读取文件数据的方法

FileReader类型实现的是一种一部文件读取机制。可以把FileReader想象成XMLHttpRequest,区别只是它读取的是文件系统,而不是远程服务器。FileReader提供一个异步API,使用该API可以在浏览器主线程中异步访问文件系统,读取文件中的数据。为了读取文件中的数据,FileReader提供了如下几个方法:

  • readAsText(file|blob [, encoding]):以纯文本形式读取文件,将读取到的文本保存在result属性中。第二个参数用于指定编码类型,可选。
  • readAsDataURL(file|blob):读取文件并将文件以数据URI的形式保存在result属性中。
  • readAsBinaryString(file|blob):读取文件并将一个字符串保存在result属性中,字符串中的每个字符表示一个字节。
  • readAsArrayBuffer(file|blob):读取文件并将一个包含文件内容的ArrayBuffer保存在result属性中。
  • abort():中断读取操作。

这些读取文件的方法为灵活地处理文件数据提供了极大的便利。例如,可以读取图像文件并将其保存为数据URI,一遍将其显示给用户;或者为了解析方便,可以将文件读取为文本形式。

3.2 FileReader的兼容性

实现了FileAPI的所有浏览器都支持readAsText()和readAsDataURL()方法。但是IE10 PR 2不支持readAsBinaryString()和readAsArrayBuffer()。IE9及其以下版本浏览器不支持FileReader API。

检查当前浏览器是否支持FileReader API的方法如下:

if(typeof FileReader == "undefined") {
    alert("您的浏览器不支持FileReader API.");
} else {
    var reader = new FileReader();
}

3.3 FileReader的事件

由于读取文件的过程是异步的,因此FileReader也提供了几个事件,常用的有:

  • progress() :数据读取中。
  • error():数据读取出错时触发。
  • load():数据读取成功完成时触发。
  • abort():数据读取中断时触发。
  • loadstart():数据读取开始时触发。
  • loadend():数据读取完成时触发,无论成功或失败。

每过50ms左右,就回触发一次progress事件通过事件对象可以获得与XHR的progress事件相同的信息(属性):lengthComputable、loaded和total。每次progress事件中都可以通过FileReader的result属性读取到文件内容。

当无法读取文件时,就会触发error事件。触发error事件时,相关的信息将保存到FileReader的error属性中。这个属性将保存一个对象,该对象只有一个属性code,即错误码。这个错误码的属性值如下:

  • 1:表示未找到文件;
  • 2:表示安全性错误;
  • 3:表示读取中断;
  • 4:表示文件不可读;
  • 5:表示编码错误。

文件加载成功后会触发load事件。如果发生了error事件,就不会发生load事件。

例子:

<input type="file" name="" id="filesList">
<div id="progress"></div>
<div id="output"></div>

<script type="text/javascript">
    var filesList = document.getElementById("filesList");
    filesList.addEventListener("change", function(e) {
        var info = "",
        output = document.getElementById("output"),
        progress = document.getElementById("progress"),
        files = this.files,
        type = "default",
        reader = new FileReader();

        if(/image/.test(files[0].type)) {
            reader.readAsDataURL(files[0]);
            type = "image";
        } else {
            reader.readAsText(files[0]);
            type = "text";
        }

        reader.onerror = function() {
            output.innerHTML = "error code: " + reader.error.code;
        };
        reader.onprogress = function(event) {
            console.log("lengthComputable: " + event.lengthComputable);
            if(event.lengthComputable) {
                progress.innerHTML = event.loaded + "/ " + event.total;
            }
        };
        reader.onload = function() {
            var html = "";
            switch(type) {
                case "image":
                    html = "<img src=\"" + reader.result + "\">";
                    break;
                case "text":
                    html = reader.result.toString();
                    break;
            }
            output.innerHTML = html;
        }
    });
</script>

在这个例子中,读取了表单字段中选择的文件,并将其内容显示在页面中如果是图片类型的文件,则将其保存为数据URI,并显示出读取的内容;如果是文件而不是图片,则以字符串形式读取并显示其内容。

四. 推荐阅读

HTML5 File API 规范(官方网站):https://www.w3.org/TR/FileAPI/

本文作者:子匠_Zijor,转载请注明出处:http://www.dengzhr.com/js/922