• HTML5 FileReader


    这里将继续介绍一下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="'+ 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,您可以试一下:

    分度读取文件:

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

  • 相关阅读:
    告别ThinkPHP6的异常页面, 让我们来拥抱whoops吧
    ThinkPHP6 上传图片代码demo
    【ThinkPHP6:从TP3升级到放弃】1. 前言及准备工作
    PHP数字金额转换大写金额
    提高PHP开发效率, PhpStorm必装的几款插件
    5分钟弄懂Docker!
    GitHub 上排名前 100 的 IOS 开源库简介
    GitHub 上排名前 100 的 Android 开源库简介
    android线程消息传递机制——Looper,Handler,Message
    Android Activity:四种启动模式,Intent Flags和任务栈
  • 原文地址:https://www.cnblogs.com/student-programmer/p/6743572.html
Copyright © 2020-2023  润新知