HTML5 FileReader

摘要:
F、 类型。match){//设置错误消息varli=document.createElement;li.innerHTML=''+f.name+'不是图片文件。';ul.appendChild;continue;}varreader=newFileReader();reader.onload=;//读取文件内容读取器。readAsDataURL;}}如果{document.getElementById.addEventListener;}否则{document.write;}从上述代码中,调用FileReader的readAsDataURL接口将启动文件内容的异步加载。加载数据后,可以通过onload事件处理中读取器的result属性获取文件内容。

这里将继续介绍一下FileReader,用FileReader具体地读取文件内容。

         NOTE: 在chrome浏览器上本地测试的时候,即以file://xxx这种形式测试本文中的demo,会出现FileReader读取不到内容的情况,表现为 FileReader的result为空或者FileReader根本就没有去读取文件内容,FileReader各个事件没有触发;这种情况我想应该是 类似于chrome不允许添加本地cookie那样,chrome也不允许以file://xxx这种页面上的js代码访问文件内容;解决办法很简单,只 需要将测试文件放到一个web服务器上,以http://xxx形式访问即可。

一、FileReader读取文件内容

       前文主要介绍获取文件句柄的方法,接下来我们就要利用该文件句柄来读取文件内容,这是通过FileReader来实现的,通过FileReader接口,我们可以异步地将文件内容加载到内存中,赋予某个js变量。

       FileReader具体支持哪些方法和事件,这里就不介绍了,有兴趣的可以去w3c官网上看看FileReader介绍,这里主要介绍一下FileReader两个常见应用。

1、预览本地图片

       这里主要用到FileReader的readAsDataURL方法,通过将图片数据读取成Data URL的方法,将图片展示出来,关于DATA URI

示例脚本:

  1. function fileSelect(e) {  
  2.     e = e || window.event;  
  3.        
  4.     var files = e.target.files;  //FileList Objects      
  5.     var ireg = /image/.*/i,  
  6.         p = document.getElementById('Preview');  
  7.            
  8.     var ul = document.getElementById('Errors');  
  9.     for(var i = 0, f; f = files[i]; i++) {  
  10.         if(!f.type.match(ireg)) {  
  11.             //设置错误信息  
  12.             var li = document.createElement('li');  
  13.             li.innerHTML = '<li>' + f.name +'不是图片文件.</li>';  
  14.                
  15.             ul.appendChild(li);  
  16.                
  17.             continue;  
  18.         }  
  19.            
  20.         var reader = new FileReader();  
  21.            
  22.         reader.onload = (function(file) {  
  23.             return function(e) {  
  24.                 var span = document.createElement('span');  
  25.                 span.innerHTML = '<img class="thumb" src="http://t.zoukankan.com/student-programmer-p-6743572.html'+ this.result +'" alt="'+ file.name +'" />';  
  26.                    
  27.                 p.insertBefore(span, null);  
  28.             };  
  29.         })(f);  
  30.         //读取文件内容  
  31.         reader.readAsDataURL(f);  
  32.     }  
  33. }  
  34.        
  35. if(window.File && window.FileList && window.FileReader && window.Blob) {  
  36.     document.getElementById('Files').addEventListener('change', fileSelect, false);  
  37. else {  
  38.     document.write('您的浏览器不支持File Api');  
  39. }  


由以上代码可知,调用FileReader的readAsDataURL接口,将启动异步加载文件内容,通过给reader监听一个onload事件,将数据加载完毕后,在onload事件处理中,通过reader的result属性即可获得文件内容。

点击此处查看demo>>

        NOTE:在示例中,我给图片指定了一个height:75px的css样式,主要是为了让浏览器对图片进行等比缩放处理,所以在浏览器中展示出来的图片 并不是原始大小的图片,而是经过浏览器自动等比缩放的图片;如果需要查看原始尺寸图片,可点击相应图片;再次单击该图片,则恢复小图片。

2、预览文本文件

        这里主要用到FileReader的readAsText,对于诸如mimetype为text/plain、text/html等文件均认为是文本文件,即minetype为text开头都能在本例中预览。

NOTE:由于需要在页面上预览文本,如果使用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. }  

点击此处查看demo>>

二、分段读取文件内容(slice)

      有的时候,一次性将一个大文件读入内存,并不是一个很好的选择(如果文件太大,使用FileReader读取文件内容,可能直接导致浏览器崩溃),w3c也想到了这种情况,所以html5允许对文件进行分段读取。

chrome以及firefox已经将File slice api调整为如下:

  1. var blob;  
  2.    
  3. if(file.webkitSlice) {  //Blob中的方法  
  4.     blob = file.webkitSlice(start, end + 1, 'text/plain;charset=UTF-8');  
  5. else if(file.mozSlice) {  
  6.     blob = file.mozSlice(start, end + 1, 'text/plain;charset=UTF-8');  
  7. }  


本例使用了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.    
  35. try {  
  36.     document.getElementById('buttons').addEventListener('click', function(e) {  
  37.         if(e.target.tagName.toLowerCase() == 'button') {  
  38.             var start = e.target.getAttribute('data-start'),  
  39.                 end = e.target.getAttribute('data-end');  
  40.                    
  41.             readBlob(start, end);  
  42.         }    
  43.     });  
  44. catch(ex) {  
  45.     alert('something error happens!')  
  46. }  

点击此处查看demo>>

NOTE:readAsBinaryString这个方法,读取的二进制字符串,在页面显示,出现中文乱码,不知道怎么解决,如果用reader.readAsText即可正常显示中文;在w3c官网上:binary string, in which every byte is represented by an integer in the range [0..255],而中文却不在[0...255]内,难道是因为这样才出现乱码?

三、FileReader进度条

       既然FileReader是异步读取文件内容,那么就应该可以监听它的读取进度。事实上,FileReader的onloadstart以及onprogress等事件,可以用来监听FileReader的读取进度。

       在onprogress的事件处理器中,提供了一个ProgressEvent对象,这个事件对象实际上继承了Event对象,提供了三个只读属 性:lengthComputable、loaded、total;通过以上几个属性,即可实时显示读取进度。w3c官网上对它的定义如下:

  1. interface ProgressEvent : Event {  
  2.   readonly attribute boolean lengthComputable;  
  3.   readonly attribute unsigned long long loaded;  
  4.   readonly attribute unsigned long long total;  
  5. };  


    如果处理的文件太大,可能会导致浏览器崩溃(chrome下一般都会崩溃掉,而firefox则不会,不过会触发FileReader的onerror事 件,文件读取失败),所以为了安全地、正常地观察到文件读取进度,我们采用分段读取的方法来测试FileReader的进度条。

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.         <id="Status"></p>  
  10.     </fieldset>  
  11. </form>  


JS代码如下:

  1. var h = {  
  2.     init: function() {  
  3.         var me = this;  
  4.            
  5.         document.getElementById('File').onchange = me.fileHandler;  
  6.         document.getElementById('Abort').onclick = me.abortHandler;  
  7.            
  8.         me.status = document.getElementById('Status');  
  9.         me.progress = document.getElementById('Progress');  
  10.         me.percent = document.getElementById('Percent');  
  11.            
  12.         me.loaded = 0;  
  13.         //每次读取1M  
  14.         me.step = 1024 * 1024;  
  15.         me.times = 0;  
  16.     },  
  17.     fileHandler: function(e) {  
  18.         var me = h;  
  19.            
  20.         var file = me.file = this.files[0];  
  21.            
  22.         var reader = me.reader = new FileReader();  
  23.            
  24.         //  
  25.         me.total = file.size;  
  26.            
  27.         reader.onloadstart = me.onLoadStart;  
  28.         reader.onprogress = me.onProgress;  
  29.         reader.onabort = me.onAbort;  
  30.         reader.onerror = me.onerror;  
  31.         reader.onload = me.onLoad;  
  32.         reader.onloadend = me.onLoadEnd;  
  33.         //读取第一块  
  34.         me.readBlob(file, 0);  
  35.     },  
  36.     onLoadStart: function() {  
  37.         var me = h;  
  38.     },  
  39.     onProgress: function(e) {  
  40.         var me = h;  
  41.            
  42.         me.loaded += e.loaded;  
  43.         //更新进度条  
  44.         me.progress.value = (me.loaded / me.total) * 100;  
  45.     },  
  46.     onAbort: function() {  
  47.         var me = h;  
  48.     },  
  49.     onError: function() {  
  50.         var me = h;  
  51.            
  52.     },  
  53.     onLoad: function() {  
  54.         var me = h;  
  55.    
  56.         if(me.loaded < me.total) {  
  57.             me.readBlob(me.loaded);  
  58.         } else {  
  59.             me.loaded = me.total;  
  60.         }  
  61.     },  
  62.     onLoadEnd: function() {  
  63.         var me = h;  
  64.            
  65.     },  
  66.     readBlob: function(start) {  
  67.         var me = h;  
  68.            
  69.         var blob,  
  70.             file = me.file;  
  71.            
  72.         me.times += 1;  
  73.            
  74.         if(file.webkitSlice) {  
  75.             blob = file.webkitSlice(start, start + me.step + 1);  
  76.         } else if(file.mozSlice) {  
  77.             blob = file.mozSlice(start, start + me.step + 1);  
  78.         }  
  79.            
  80.         me.reader.readAsText(blob);  
  81.     },  
  82.     abortHandler: function() {  
  83.         var me = h;  
  84.            
  85.         if(me.reader) {  
  86.             me.reader.abort();  
  87.         }  
  88.     }  
  89. };  
  90.    
  91. h.init();  


    例子中的进度条采用html5 progress元素来实现的。

        每次读取1M的字节(你也可以随便改步长,比如说一次一个字节,然后传一个大小为几字节的文件,也能很好地观察到进度),在一次读取完毕后,onload事件中开启下一次读取,直至整个文件都读取完毕。

         如果您的浏览器支持html5,您可以试一下:

分度读取文件:

        这个示例中,没有限制文件大小,读取大文件时,也不会出现浏览器崩溃的情况,可以正常观察到文件的读取进度。

免责声明:文章转载自《HTML5 FileReader》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇html 复选框checkbox简单5步,轻松debug K8S服务!下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

base64图片转化成文件

承接《vue截取video视频中的某一帧》视频截取后保存的是base64格式,没法上传服务器,需要转化一下 //将base64转换为文件 dataURLtoFile(dataurl, filename) { let arr = dataurl.split(',') let mime = arr[0].match(/:(.*?);/)[1];...

oracle中Blob和Clob类型的区别

一、oracle中Blob和Clob类型的区别BLOB和CLOB都是大字段类型,BLOB是按二进制来存储的,而CLOB是可以直接存储文字的。其实两个是可以互换的的,或者可以直接用LOB字段代替这两个。但是为了更好的管理ORACLE数据库,通常像图片、文件、音乐等信息就用BLOB字段来存储,先将文件转为二进制再存储进去。而像文章或者是较长的文字,就用CLOB...

TextBlob Quick Start

安装 pip install textblob import nltk pip install nltk nltk.download('punkt') # 安装一些语料库, 国内安装有问题nltk.download('averaged_perceptron_tagger') 基本操作 情感分析 该sentiment属性返回形式的namedtuple...

mockjs导致element-ui upload组件的on-progress和axios的responseType失效

公司最近换了一个新的框架,还没有仔细的研究透,就需要用新框架来开发项目了。那没办法只能走一步看一步了。 1.element-ui el-upload   项目需求中需要附件上传,那简单,就用element-ui的upload组件嘛。咦!?,上传时候的进度条呢?注册的on-process事件也不触发了!那就百度。。。。。。。哦?原来是mockjs搞得鬼。参考...

FormData、Blob、File、ArrayBuffer数据类型

XMLHttpRequest 1.0 1.0 中xmlhttpRequest有2个重要的返回属性,reposeText,reposeXml。下面的数据类型都是2.0新增的 FormData对象 我们应该都用过jQuery,其中有个方法叫做serialize(), 作用就是表单序列化,也就是以查询字符串形式获得类表单post/get的数据给Ajax请求,例如...

SQLite中如何用api操作BLOB类型的字段

在实际的编程开发当中我们经常要处理一些大容量二进制数据的存储,如图片或者音乐等等。对于这些二进制数据(blob字段)我们不能像处理普通的文本那样简单的插入或者查询,为此SQLite提供了一组函数来处理这种BLOB字段类型。下面的代码演示了如何使用这些API函数。 首先创建一个数据库,然后创建一个数据表: nsqSt = sqlite3_exec( hand...