HTML 5 关于文件读取学习笔记
HTML 5中File API是HTML 5中一大亮点,可以让我们去读取本地文件。让所有开发者兴叹!通过File API规范提供了多种访问文件接口。
浏览器对HTML 5中File相关接口的支持情况
在使用File API时,可能需要检测浏览器的支持情况,特征检测代码如下:
复制
// 检测浏览器是否支持File API相关接口.
if (window.File && window.FileReader && window.FileList && window.Blob) {
//支持滴
} else {
//不支持
alert('HTML5 File API在您的浏览器里是不完全支持的。');
}
浏览器中File API并不能想读取文件就可以读取文件的,你必须通过用户的行为才能触发文件的读取。比如,进入网页,当用户执行点击操作后,选择文件后,通过File API就可以获取文件的相关信息。支持File API的浏览器有IE10+、FireFox 3.5+、Opera 10.6+、Safari 5+、Chrome和IOS版的Safari及Android版的Webkit、UC ;当然,它们多数并不是完全支持的。
关于File对象的相关说明
在浏览器中,由于安全限制,File对象一般都是通过点击type=file的input表单、HTML 5的拖放API来获取FileList数组、通过在输入框中粘贴时,里面包含了一个或多个File对象。File对象中包含着文件的相关信息,比如文件名,文件大小,文件类型等。
对象类型 描述
File 独立文件对象,主要包含以下属性:name、size、type、lastModifiedDate及slice()方法(可以直接转成对象URL或通过Fil API读取)
FileList File对象的类数组序列(有时文件多选时,会出现)
Blob Blob对象是File类型的父类型,是File对象通过slice()方法读取整个文件的部分数据。Blob类型有两个属性size、type,当然还支持slice()方法
下面对以上属性作以简单介绍:
name:本地文件系统中的文件名
size:文件的大小,以字节为单位
type:文件的MIME类型(字符串)
lastModifiedDate:文件最后修改时间,字符串(仅Chrome支持)
下面是一个简单示例,通过表单File选择文件然后显示文件的相关信息,下面的代码:
HTML 代码:
复制
<!-- start: 输入表单 -->
<input type="file" name="file" multiple />
<!-- end: 输入表单 -->
<!-- start: 模板 -->
<div class="remark">
<p>文件名称:<!--name--></p>
<p>文件大小:<!--size--> byte</p>
<p>文件类型:<!--type--></p>
<p>文件最后修改时间:<!--lastModifiedDate--></p>
<hr/>
</div>
<!-- end: 模板 -->
JavaScript 代码:
复制
if(!(window.File && window.FileReader && window.FileList && window.Blob)) {
alert('您的浏览器不完全支持FileReader API接口,请尝试使用支持HTML 5的浏览器!');
throw new Error('browser not support File API');
}
/**
* * 解析模板文件
* @param template 模板字符串
* @param scope 模板作用域
* return [string] 解析过后的字符串
*/
function templateParse(template, scope) {
if(typeof template != "string") return ;
return template.replace(/<!--\w+--\>/gi, function(matchs) {
var returns = scope[matchs.replace(/(<!--)|(--\>)/g, "")];
return (returns + "") == "undefined"? "": returns;
});
}
window.addEventListener('load',function(){
var inputField = document.querySelector('input[name="file"]'), //表单输入框
remark = document.querySelector('div.remark'),
template = remark.innerHTML; //模板文件
inputField.addEventListener('change', function(){
var files = this.files,i= 0, t = "";
for(;i<files.length; i++) {
t += templateParse(template, files[i]);
}
remark.innerHTML = t;
},false);
}, false);
FileReader类型
与以上数据结构结合使用时,FileReader可以用JavaScript事件来处理异步读取文件。因为可以监控读取进度、找出错误并确定加载何时完成。FileReader与XMLHttpRequest的事件模型有很多相似之处。区别就在与FileReader是读取本地文件,而XMLHttpRequest是用来读取服务器上的文件。下面是一段简单的代码,来说明File类型文件:
FileReader类型实现了一种异步读取文件的方式;提供了几个方法:
readAsText(file, [encoding]):以纯文件的形式读取文件,并将取到的文本保存在实例对象的result属性中。第二个参数表示读取的编码类型,可选传
readAsDataURL(file):读取文件,并将数据以数据URL的形式保存在实例对象result属性中,如可以直接赋给图片的src等 (会转成base64编码)
readAsBinaryString(file):读取文件并将一个字符串保存在result属性中,字符串中的每个字符表示一个字节 (IE 10中尚未实现)
readAsArrayBuffer(file):读取文件并将一个包含文件内容的ArrayBuffer保存在result属性中 (IE 10中尚未实现)
abort():终止当前的读取操作
由于读取文件的过程是异步的,因此FileReader也就提供了相应的事件处理,如下:
progress:通常用来跟踪当前文件读取的进度,它一般在文件读取的过程中,每隔50ms左右触发一次。通过事件对象可以获取与XHR的progress事件相同的信息:lengthComputable、loaded和total。
error:在读取过程中,产生错误时的回调函数;如果产生了error事件,那么load事件就不会再产生了。触发error事件,相关的信息将会保存到FileReader的error属性中,这个属性是一个对象,只有一个属性code,即错误码:1、文件未找到;2、安全性错误;3、读取中断;4、文件不可读。
load:文件读取成功的时回调
loadstart:开始读文件时的回调
abort:当读文件操作被终止时的回调
loadend:当文件读取完成时的回调(特别注意:这个事件是无论文件读取成功或是失败,都是会被执行的)
读取文件的部分内容
有的时候,为了读取文件的一部分而不是全部时,我们需要用到File对象的slice()方法。这个方法在FireFox中的实现叫mozSlice(),在Chrome中叫webkitSlice()。slice()方法接收两个参数,起始的字节及要读取的字节;方法返回一个Blob实例。以下是一个通用的处理函数:
复制
function blobSlice(blob, startByte, length){
if (Blob.slice) {
return blob.slice(startByte, length);
} else if(blob.webkitSlice) {
return blob.webkitSlice(startByte, length);
} else if(blob.mozSlice) {
return blob.mozSlice(startByte, length);
} else {
return null;
}
}
Blob类型有一个size属性和type属性,且也有一个slice()方法,因为我们可以继续切割数据。FileReader也是可以从Blob中读取数据,如下例所示(以选择一个大于32B的文件):
HTML 代码:
复制
<label for="text">请选择文件<input type="file" id="text" name="text" accept="text/*" /></label>
<p id="textRemark">暂无内容</p>
Js 代码:
复制
window.addEventListener('load',function(){
var textInput = document.querySelector('input[name="text"]');
textInput.addEventListener('change',function(){
var files = this.files[0],
reader = new FileReader(),
blob = blobSlice(files, 0, 32),
textRemark = document.querySelector('p#textRemark');
if(blob) {
//读取文件
reader.readAsText(blob);
//读取出错
reader.addEventListener('error',function(){
textRemark.innerHTML = '读取错误代码:' + reader.error.code;
},false);
//读取成功
reader.addEventListener('load',function(e){
textRemark.innerHTML = this.result;
},false);
} else {
alert('你的浏览器不支持Slice方法');
}
},false);
},false);
对象URL
对象URL也被称为blob URL,指的是引用保存在File或Blob中数据的URL。使用对象URL的好处是,我们没有必要去调用File Reader就可以读取到对应的数据。为了创建对象URL,可以使用window.URL.createObjectURL()方法创建,并传入一个File或Bolb对象。其兼容的处理方案如下:
复制
function createObjectURL(blob) {
if(window.URL) {
return window.URL.createObjectURL(blob);
}else if(window.webkitURL) {
return window.webkitURL.createObjectUrl(blob);
}else {
return null;
}
}
以下是一个示例,通过blob插入到img标签中:
HTML代码
复制
<label for="imageList">请选择文件<input type="file" id="imageList" multiple name="image" accept="image/*" /></label>
<p id="imageRemark">暂无内容</p>
JS 代码
复制
window.addEventListener('load',function(){
var imageList = document.getElementById('imageList'),
imageRemark = document.getElementById('imageRemark');
imageList.addEventListener('change',function(e){
if(!this.files.length) return ;
var url = null,
i= 0,
l=this.files.length,
html = '';
for(;i<l;i++){
url = createObjectURL(this.files[i]);
if(url) {
html+= '<img src=\"' + url +'\"/>';
}
url = null;
}
imageRemark.innerHTML = html;
},false);
},false);
以上代码中,其实是直接读取图片文件放入到内存中,然后创建对象URL来形成内存中的引用。直接插入到img标签上,相比用FileReader来讲,效率确实高出很多。但由于文件读取是放在内存中,如果存在对图片的引用,那么图片占用的内存就不会被释放。要手动去清除内存的话,就可以直接把对象URL当作参数的形式传给window.URL.revokeObjectURL()。由于不同浏览器带的前缀不同,所以就有了以下的兼容函数:
复制
function revokeObject(url){
if(window.URL) {
window.URL.revokeObjectURL(url);
} else if(window.webkitURL) {
window.webkitURL.revokeObjectURL(url)
}
}
一般来说,在页面卸载后,会自动释放对象URL所占用的内存。不过有时,为了及时释放内存,就可以使用上面的方法