HTML5之FileReader接口读取文件
- 用来把文件读入内存,并且读取文件中的数据。FileReader接口提供了一个异步API,使用该API可以在浏览器主线程中异步访问文件系统,读取文件中的数据。到目前为止,只有FF3.6+和Chrome6.0+实现了FileReader接口。
1.FileReader接口的方法
-
FileReader接口有4个方法,其中3个用来读取文件,另一个用来中断读取。无论读取成功或失败,方法并不会返回读取结果,这一结果存储在result属性中。
-
方法名 参数 描述
-
readAsBinaryString file 将文件读取为二进制编码
-
readAsText file,[encoding] 将文件读取为文本,其中第二个参数是文本的编码方式,默认值为 UTF-8
-
readAsDataURL file 将文件读取为DataURL
-
abort (none) 终端读取操作
2.FileReader接口事件
-
FileReader接口包含了一套完整的事件模型,用于捕获读取文件时的状态。
-
事件 描述
-
onabort 中断
-
onerror 出错
-
onloadstart 开始
-
onprogress 正在读取
-
onload 成功读取
-
onloadend 读取完成,无论成功失败
3.FileReader接口的使用
-
文件一旦开始读取,无论成功或失败,实例的 result 属性都会被填充。如果读取失败,则 result 的值为 null ,否则即是读取的结果,绝大多数的程序都会在成功读取文件的时候,抓取这个值。
-
var reader=new FileReader();
-
reader.onload = function() {
-
this.result;
-
};
-
//
-
var reader=new FileReader();
-
reader.onload = function(e) {
-
e.target.result;
-
};
-
例子1:
1 <!DOCTYPE HTML> 2 <html> 3 <head> 4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 5 <title>无标题文档</title> 6 <style> 7 img{ 8 width:100px; 9 height:100px; 10 } 11 </style> 12 </head> 13 <body> 14 <script type="text/javascript"> 15 if(typeof FileReader == 'undefined'){ //判断浏览器是否支持FileReader接口 16 var div=document.getElementById("dd"); 17 div.innerHTML='你的浏览器不支持FileReader接口!'; 18 document.getElementById("file").setAttribute("disabled","disabled"); 19 document.getElementById("filea").setAttribute("disabled","disabled"); 20 document.getElementById("fileb").setAttribute("disabled","disabled"); 21 } 22 23 function show(){ 24 var file=document.getElementById("file").files[0]; 25 var reg=/image/w+/; 26 if(!reg.test(file.type)){ //判断是否为图片 27 return false; 28 } 29 if(file){ 30 var reader = new FileReader(); 31 reader.onload = function ( event ) { 32 var txt = event.target.result; 33 var img = document.createElement("img"); 34 img.src = txt; 35 document.getElementById("content").appendChild( img ); 36 } 37 } 38 reader.readAsDataURL(file); 39 } 40 function aShow(){ 41 var file=document.getElementById("filea").files[0]; 42 if(file){ 43 var reader=new FileReader(); 44 reader.onload=function(){ 45 var cona=document.getElementById("contenta"); 46 cona.innerHTML=this.result; 47 } 48 } 49 reader.readAsBinaryString(file); 50 } 51 function bShow(){ 52 var file=document.getElementById("fileb").files[0]; 53 if(file){ 54 var reader=new FileReader(); 55 reader.onload=function(e){ 56 var conb=document.getElementById("contentb"); 57 conb.innerHTML=e.target.result; 58 } 59 } 60 reader.readAsText(file); 61 } 62 </script> 63 <div id="dd"> </div> 64 <p>图像:<input type="file" name="file" id='file' onchange='show()'/></p> 65 <p id='content'></p> 66 <p>二进制文件:<input type="file" name="file" id='filea' onchange='aShow()'/></p> 67 <p id='contenta'></p> 68 <p>文本文件:<input type="file" name="file" id='fileb' onchange='bShow()'/></p> 69 <p id='contentb'></p> 70 </body> 71 </html>
-
例子2:兼容IE的上传图片
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 5 <title>图片上传本地预览</title> 6 <style type="text/css"> 7 #preview{width:547px;height:626px;border:1px solid #000;overflow:hidden;} 8 #imghead {filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=image);} 9 input{margin-top:20px;} 10 </style> 11 <script type="text/javascript"> 12 13 14 //图片上传预览 IE是用了滤镜。 15 function previewImage(file) 16 { 17 var MAXWIDTH = 547; 18 var MAXHEIGHT = 626; 19 var div = document.getElementById('preview'); 20 if (file.files && file.files[0]) 21 { 22 div.innerHTML ='<img id=imghead>'; 23 var img = document.getElementById('imghead'); 24 img.onload = function(){ 25 var rect = clacImgZoomParam(MAXWIDTH, MAXHEIGHT, img.offsetWidth, img.offsetHeight); 26 img.width = rect.width; 27 img.height = rect.height; 28 // img.style.marginLeft = rect.left+'px'; 29 img.style.marginTop = rect.top+'px'; 30 } 31 var reader = new FileReader(); 32 reader.onload = function(evt){img.src = evt.target.result;} 33 reader.readAsDataURL(file.files[0]); 34 } 35 else //兼容IE 36 { 37 var sFilter='filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=scale,src="'; 38 file.select(); 39 var src = document.selection.createRange().text; 40 div.innerHTML = '<img id=imghead>'; 41 var img = document.getElementById('imghead'); 42 img.filters.item('DXImageTransform.Microsoft.AlphaImageLoader').src = src; 43 var rect = clacImgZoomParam(MAXWIDTH, MAXHEIGHT, img.offsetWidth, img.offsetHeight); 44 status =('rect:'+rect.top+','+rect.left+','+rect.width+','+rect.height); 45 div.innerHTML = "<div id=divhead style='"+rect.width+"px;height:"+rect.height+"px;margin-top:"+rect.top+"px;"+sFilter+src+""'></div>"; 46 } 47 } 48 function clacImgZoomParam( maxWidth, maxHeight, width, height ){ 49 var param = {top:0, left:0, width, height:height}; 50 if( width>maxWidth || height>maxHeight ) 51 { 52 rateWidth = width / maxWidth; 53 rateHeight = height / maxHeight; 54 55 if( rateWidth > rateHeight ) 56 { 57 param.width = maxWidth; 58 param.height = Math.round(height / rateWidth); 59 }else 60 { 61 param.width = Math.round(width / rateHeight); 62 param.height = maxHeight; 63 } 64 } 65 66 param.left = Math.round((maxWidth - param.width) / 2); 67 param.top = Math.round((maxHeight - param.height) / 2); 68 return param; 69 } 70 </script> 71 </head> 72 <body> 73 74 <input type="file" onchange="previewImage(this)" /> 75 <div id="preview"> 76 <img id="imghead" src=''> 77 </div> 78 </body> 79 </html>
-
示例3:有上传进度条
-
既然FileReader是异步读取文件内容,那么就应该可以监听它的读取进度。事实上,FileReader的onloadstart以及onprogress等事件,可以用来监听FileReader的读取进度。
-
在onprogress的事件处理器中,提供了一个ProgressEvent对象,这个事件对象实际上继承了Event对象,提供了三个只读属性:lengthComputable、loaded、total;通过以上几个属性,即可实时显示读取进度。w3c官网上对它的定义如下:
-
interface ProgressEvent : Event {
-
readonly attribute boolean lengthComputable;
-
readonly attribute unsigned long long loaded;
-
readonly attribute unsigned long long total;
-
};
-
如果处理的文件太大,可能会导致浏览器崩溃(chrome下一般都会崩溃掉,而firefox则不会,不过会触发FileReader的onerror事件,文件读取失败),所以为了安全地、正常地观察到文件读取进度,我们采用分段读取的方法来测试FileReader的进度条。
1 <!DOCTYPE HTML> 2 <html> 3 <head> 4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 5 <title>无标题文档</title> 6 7 </head> 8 9 <body> 10 <form> 11 <fieldset> 12 <legend>分度读取文件:</legend> 13 <input type="file" id="file" /> 14 <input type="button" value="中断" id="Abort" /> 15 <p> 16 <label>读取进度:</label><progress id="Progress" value="0" max="100"></progress> 17 </p> 18 <p id="Status"></p> 19 </fieldset> 20 </form> 21 <script> 22 var h = { 23 init: function() { 24 var me = this; 25 26 document.getElementById('file').onchange = me.fileHandler; 27 document.getElementById('Abort').onclick = me.abortHandler; 28 29 me.status = document.getElementById('Status'); 30 me.progress = document.getElementById('Progress'); 31 me.percent = document.getElementById('Percent'); 32 33 me.loaded = 0; 34 //每次读取1M 35 me.step = 1024 * 1024; 36 me.times = 0; 37 }, 38 fileHandler: function(e) { 39 var me = h; 40 41 var file = me.file = this.files[0]; 42 43 var reader = me.reader = new FileReader(); 44 45 // 46 me.total = file.size; 47 48 reader.onloadstart = me.onLoadStart; 49 reader.onprogress = me.onProgress; 50 reader.onabort = me.onAbort; 51 reader.onerror = me.onerror; 52 reader.onload = me.onLoad; 53 reader.onloadend = me.onLoadEnd; 54 //读取第一块 55 me.readBlob(file, 0); 56 }, 57 onLoadStart: function() { 58 var me = h; 59 }, 60 onProgress: function(e) { 61 var me = h; 62 63 me.loaded += e.loaded; 64 //更新进度条 65 me.progress.value = (me.loaded / me.total) * 100; 66 }, 67 onAbort: function() { 68 var me = h; 69 }, 70 onError: function() { 71 var me = h; 72 73 }, 74 onLoad: function() { 75 var me = h; 76 77 if(me.loaded < me.total) { 78 me.readBlob(me.loaded); 79 } else { 80 me.loaded = me.total; 81 } 82 }, 83 onLoadEnd: function() { 84 var me = h; 85 86 }, 87 readBlob: function(start) { 88 var me = h; 89 90 var blob, 91 file = me.file; 92 93 me.times += 1; 94 95 if(file.webkitSlice) { 96 blob = file.webkitSlice(start, start + me.step + 1); 97 } else if(file.mozSlice) { 98 blob = file.mozSlice(start, start + me.step + 1); 99 } 100 101 me.reader.readAsText(blob); 102 }, 103 abortHandler: function() { 104 var me = h; 105 106 if(me.reader) { 107 me.reader.abort(); 108 } 109 } 110 }; 111 112 h.init(); 113 </script> 114 </body> 115 </html>
1 <form> 2 <fieldset> 3 <legend>分度读取文件:</legend> 4 <input type="file" id="File" /> 5 <input type="button" value="中断" id="Abort" /> 6 <p> 7 <label>读取进度:</label><progress id="Progress" value="0" max="100"></progress> 8 </p> 9 <p id="Status"></p> 10 </fieldset> 11 </form> 12 JS代码如下: 13 14 var h = { 15 init: function() { 16 var me = this; 17 18 document.getElementById('File').onchange = me.fileHandler; 19 document.getElementById('Abort').onclick = me.abortHandler; 20 21 me.status = document.getElementById('Status'); 22 me.progress = document.getElementById('Progress'); 23 me.percent = document.getElementById('Percent'); 24 25 me.loaded = 0; 26 //每次读取1M 27 me.step = 1024 * 1024; 28 me.times = 0; 29 }, 30 fileHandler: function(e) { 31 var me = h; 32 33 var file = me.file = this.files[0]; 34 35 var reader = me.reader = new FileReader(); 36 37 // 38 me.total = file.size; 39 40 reader.onloadstart = me.onLoadStart; 41 reader.onprogress = me.onProgress; 42 reader.onabort = me.onAbort; 43 reader.onerror = me.onerror; 44 reader.onload = me.onLoad; 45 reader.onloadend = me.onLoadEnd; 46 //读取第一块 47 me.readBlob(file, 0); 48 }, 49 onLoadStart: function() { 50 var me = h; 51 }, 52 onProgress: function(e) { 53 var me = h; 54 55 me.loaded += e.loaded; 56 //更新进度条 57 me.progress.value = (me.loaded / me.total) * 100; 58 }, 59 onAbort: function() { 60 var me = h; 61 }, 62 onError: function() { 63 var me = h; 64 65 }, 66 onLoad: function() { 67 var me = h; 68 if(me.loaded < me.total) { 69 me.readBlob(me.loaded); 70 } else { 71 me.loaded = me.total; 72 } 73 }, 74 onLoadEnd: function() { 75 var me = h; 76 77 }, 78 readBlob: function(start) { 79 var me = h; 80 81 var blob, 82 file = me.file; 83 84 me.times += 1; 85 86 if(file.webkitSlice) { 87 blob = file.webkitSlice(start, start + me.step + 1); 88 } else if(file.mozSlice) { 89 blob = file.mozSlice(start, start + me.step + 1); 90 } 91 92 me.reader.readAsText(blob); 93 }, 94 abortHandler: function() { 95 var me = h; 96 97 if(me.reader) { 98 me.reader.abort(); 99 } 100 } 101 }; 102 h.init();
4.预览文本文件
-
这里主要用到FileReader的readAsText,对于诸如mimetype为text/plain、text/html等文件均认为是文本文件,即minetype为text开头都能在本例中预览。
-
由于需要在页面上预览文本,如果使用innerHTML插入文本的话,则需要对html中一些特殊字符进行实体编码,这样才能保证正常显示文本。
-
encodeHTML方法:
1 function encodeHTML(source) { 2 return source 3 .replace(/&/g, '&') 4 .replace(/</g, '<') 5 .replace(/>/g, '>') 6 .replace(/"/, '"') 7 .replace(/'/, '''); 8 }; 9 function fileSelect(e) { 10 e = e || window.event; 11 12 var files = e.target.files; //FileList Objects 13 var ireg = /text/.*/i, 14 p = document.getElementById('Preview'); 15 16 var ul = document.getElementById('Errors'); 17 for(var i = 0, f; f = files[i]; i++) { 18 console.log(f.type); 19 if(!f.type.match(ireg)) { 20 //设置错误信息 21 var li = document.createElement('li'); 22 li.innerHTML = '<li>' + f.name +'不是文本文件.</li>'; 23 24 ul.appendChild(li); 25 26 continue; 27 } 28 29 var reader = new FileReader(); 30 31 reader.onload = (function(file) { 32 return function(e) { 33 var div = document.createElement('div'); 34 div.className = "text" 35 div.innerHTML = encodeHTML(this.result); 36 37 p.insertBefore(div, null); 38 }; 39 })(f); 40 //读取文件内容 41 reader.readAsText(f); 42 } 43 } 44 45 if(window.File && window.FileList && window.FileReader && window.Blob) { 46 document.getElementById('Files').addEventListener('change', fileSelect, false); 47 } else { 48 document.write('您的浏览器不支持File Api'); 49 }
5、分段读取文件内容(slice)
-
有的时候,一次性将一个大文件读入内存,并不是一个很好的选择(如果文件太大,使用FileReader读取文件内容,可能直接导致浏览器崩溃),w3c也想到了这种情况,所以html5允许对文件进行分段读取。
-
chrome以及firefox已经将File slice api调整为如下:
-
var blob;
-
if(file.webkitSlice) { //Blob中的方法
-
blob = file.webkitSlice(start, end + 1, 'text/plain;charset=UTF-8');
-
} else if(file.mozSlice) {
-
blob = file.mozSlice(start, end + 1, 'text/plain;charset=UTF-8');
-
}
-
本例使用了FileReader的onloadend事件来检测读取成功与否,如果用onloadend则必须检测一下FileReader
readyState,因为read abort时也会触发onloadend事件,如果我们采用onload,则可以不用检测readyState。
1 function readBlob(start, end) { 2 var files = document.getElementById('file').files; 3 4 if(!files.length) { 5 alert('请选择文件'); 6 return false; 7 } 8 9 var file = files[0], 10 start = parseInt(start, 10) || 0, 11 end = parseInt(end, 10) || (file.size - 1); 12 13 var r = document.getElementById('range'), 14 c = document.getElementById('content'); 15 16 var reader = new FileReader(); 17 18 reader.onloadend = function(e) { 19 if(this.readyState == FileReader.DONE) { 20 c.textContent = this.result; 21 r.textContent = "Read bytes: " + (start + 1) + " - " + (end + 1) + " of " + file.size + " bytes"; 22 } 23 }; 24 var blob; 25 26 if(file.webkitSlice) { //Blob中的方法 27 blob = file.webkitSlice(start, end + 1, 'text/plain;charset=UTF-8'); 28 } else if(file.mozSlice) { 29 blob = file.mozSlice(start, end + 1, 'text/plain;charset=UTF-8'); 30 } 31 32 reader.readAsBinaryString(blob); 33 }; 34 try { 35 document.getElementById('buttons').addEventListener('click', function(e) { 36 if(e.target.tagName.toLowerCase() == 'button') { 37 var start = e.target.getAttribute('data-start'), 38 end = e.target.getAttribute('data-end'); 39 40 readBlob(start, end); 41 } 42 }); 43 } catch(ex) { 44 alert('something error happens!') 45 }