简介
在HTML5中,文件选择标签file增加了如下两个属性:
- multiple:设定当前元素可以选取多个文件。
- accept:设定当前选择器可以选择的MIME类型或后缀名。
<input type="file" multiple name="" id="myfilePhoto" value="" accept="image/jpg, image/png">
于此同时,其出现了FileReader对象,使用FileReader对象,web应用程序可以异步的读取存储在用户计算机上的文件(或者原始数据缓冲)内容,可以使用File对象或者Blob对象来指定所要处理的文件或数据。
FileReader:是window对象的一个构造函数,用于读取文件选择标签选择的File的Dom对象。即用来把文件选择的信息读入内存,并且读取文件中的数据。其接口提供了一个异步API,使用该API可以在浏览器主线程中异步访问文件系统,读取文件中的数据。为了安全FileReader可以读取表单上已经选择的文件,不能读取本地文件,它以二进制信息的方式读取表单文件:主要用于大文件的信息读取。
特点:
- 读取后,二进制信息在浏览器内存中,批量的向服务器进行传输。
- 一般要配合后台程序,第三方插件共同完成
- 断点下载和断点上传
使用介绍
创建FileReader对象
想要创建一个FileReader对象,很简单,如下:
var fr = new FileReader();
FileReader的状态常量:
|常量名 | 值 | 描述
|-
|EMPTY | 0 | 还没有加载任何数据.
|LOADING | 1 | 数据正在被加载.
|DONE | 2 | 已完成全部的读取请求.
FileReader接口的方法
FileReader接口有5个方法,其中4个用来读取文件,另一个用来中断读取。无论读取成功或失败,方法并不会直接返回读取结果,这一结果存储在result属性中。
FileReader接口的方法:
|方法名 | 参数 | 描述
|-
|readAsArrayBuffer | file | 将文件读取为一个ArrayBuffer对象以表示所读取文件的内容.
|readAsBinaryString | file | 将文件读取为二进制编码
|readAsText | file,[encoding] | 将文件读取为文本
|readAsDataURL | file | 将文件读取为DataURL,读取的内容是加密以后的本地文件路径
|abort | (none) | 终端读取操作
FileReader的属性:
|属性名 | 类型 | 描述
|-
|error | DOMError | 在读取文件时发生的错误. 只读.
|readyState | unsigned short | 表明FileReader对象的当前状态. 值为State constants中的一个. 只读
|result | jsval | 读取到的文件内容.这个属性只在读取操作完成之后才有效,并且数据的格式取决于读取操作是由哪个方法发起的. 只读.
FileReader接口事件
FileReader接口包含了一套完整的事件模型,用于捕获读取文件时的状态。
FileReader接口的事件:
|事件 | 描述
|-
|onabort | 中断
|onerror | 出错
|onloadstart | 开始
|onprogress | 正在读取
|onload | 成功读取
|onloadend | 读取完成,无论成功失败
实例说明一切:
讲完这些大家其实还是不知道怎么用,于是,实例来说明一切:
<!-- multiple多个文件 -->
<input type="file" multiple name="" id="myfilePhoto" value="" accept="image/jpg, image/png">
<ul class="fileUl"></ul>
<script>
document.getElementById('myfilePhoto').addEventListener("change",function(){
var inputFile = document.getElementById('myfilePhoto');
for(var i = 0; i<inputFile.files.length ;i++){
var fr = new FileReader(); // 这个FileReader应该对应于每一个读取的文件都需要重新new一个
var files = inputFile.files[i]; // files可以获取当前文件输入框中选择的所有文件,返回列表
fr.readAsDataURL(files); // 读取的内容是加密以后的本地文件路径
fr.onload = function(e){ // 数据读取完成时触发onload对应的响应函数
// e.target是FileReader等同于fr
var ulLi = document.createElement('li');
var ulLiA = document.createElement('a');
var ulLiimg = document.createElement('img');
ulLiimg.src = e.target.result
ulLiA.appendChild(ulLiimg);
ulLi.appendChild(ulLiA);
console.log(document.getElementsByClassName('fileUl'))
document.getElementsByClassName('fileUl')[0].appendChild(ulLi)
}
}
});
</script>
<script>
function updateSize() {
var nBytes = 0;
var oFiles = document.getElementById("uploadInput").files;
var nFiles = oFiles.length;
for (var nFileId = 0; nFileId < nFiles; nFileId++) {
nBytes += oFiles[nFileId].size;
}
var sOutput = nBytes + " bytes";
var aMultiples = ["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"];
var nMultiple = 0, nApprox = nBytes / 1024;
for ( ; nApprox > 1; nApprox /= 1024, nMultiple++) {
sOutput = nApprox.toFixed(3) + " " + aMultiples[nMultiple] + " (" + nBytes + " bytes)";
}
document.getElementById("fileNum").innerHTML = nFiles;
document.getElementById("fileSize").innerHTML = sOutput;
}
</script>
<p>
<input id="uploadInput" type="file" name="myFiles" onchange="updateSize();" multiple>
选择的文件数:<span id="fileNum">0</span>
总共大小:<span id="fileSize">0</span>
</p>
注意:在遍历时把 var fileReader = new FileReader(); 放到了循环之外,会导致了 Uncaught InvalidStateError: Failed to execute 'readAsDataURL' on 'FileReader': The object is already busy reading Blobs.错误,这个FileReader应该对应于每一个读取的文件都需要重新new一个。
onload只在所有数据读取成功完成时触发,并且结果也只在onload之后才有。
问题解释:因为你每次循环如果只new了一次相当与你只创建一个fileReader对象,可是我们每次循环时,拿到的文件信息却是不同的,这就好比你雇了一个员工,要求他同时去打扫卫生间又打扫办公室又去浇花,他只能先干完一件才能去干另一件,所以它就会给你报错:The object is already busy reading Blobs.对象已经在忙着阅读Blobs-即忙着处理不可变的类似文件对象的原始数据。你一定会疑问我是for循环一次完成了啊?你别忘了fr.onload是一个异步的,你for一次完成,但是处理信息并没有完成,这就是你指挥员工命令已完成,但是,员工干活却还在干,因为干活也是要时间的。
FileReader接口的使用
实例结束再来个大点案例:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script type="text/javascript">
var result=document.getElementById("result");
var file=document.getElementById("file");
//判断浏览器是否支持FileReader接口
if(typeof FileReader == 'undefined'){
result.InnerHTML="<p>你的浏览器不支持FileReader接口!</p>";
//使选择控件不可操作
file.setAttribute("disabled","disabled");
}
function readAsDataURL(){
//检验是否为图像文件
var file = document.getElementById("file").files[0];
if(!/image\/\w+/.test(file.type)){
alert("看清楚,这个需要图片!");
return false;
}
var reader = new FileReader();
//将文件以Data URL形式读入页面
reader.readAsDataURL(file);
reader.onload=function(e){
var result=document.getElementById("result");
//显示文件
result.innerHTML='![](' + this.result +')';
}
}
function readAsBinaryString(){
var file = document.getElementById("file").files[0];
var reader = new FileReader();
//将文件以二进制形式读入页面
reader.readAsBinaryString(file);
reader.onload=function(f){
var result=document.getElementById("result");
//显示文件
result.innerHTML=this.result;
}
}
function readAsText(){
var file = document.getElementById("file").files[0];
var reader = new FileReader();
//将文件以文本形式读入页面
reader.readAsText(file);
reader.onload=function(f){
var result=document.getElementById("result");
//显示文件
result.innerHTML=this.result;
}
}
</script>
<p>
<label>请选择一个文件:</label>
<input type="file" id="file" />
<input type="button" value="读取图像" onclick="readAsDataURL()" />
<input type="button" value="读取二进制数据" onclick="readAsBinaryString()" />
<input type="button" value="读取文本文件" onclick="readAsText()" />
</p>
<div id="result" name="result"></div>
</body>
</html>