HTML5之FileReader接口读取文件

发表于2016-05-20 14:55:44

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;  
    }; 

例子一

<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>无标题文档</title>
<style>
img{
    width:100px;
    height:100px;
}
</style>
</head>
<body>
<script type="text/javascript">
if(typeof FileReader == 'undefined'){    //判断浏览器是否支持FileReader接口  
    var div=document.getElementById("dd");
    div.innerHTML='你的浏览器不支持FileReader接口!';
    document.getElementById("file").setAttribute("disabled","disabled");
    document.getElementById("filea").setAttribute("disabled","disabled");
    document.getElementById("fileb").setAttribute("disabled","disabled");
}
function show(){
    var file=document.getElementById("file").files[0];
    var reg=/image\/\w+/;
    if(!reg.test(file.type)){    //判断是否为图片
        return false;
    }
    if(file){
        var reader = new FileReader();
        reader.onload = function ( event ) {
            var txt = event.target.result;
            var img = document.createElement("img");
            img.src = txt;
            document.getElementById("content").appendChild( img );
        }
    }
    reader.readAsDataURL(file);
} 
function aShow(){
    var file=document.getElementById("filea").files[0];
    if(file){
        var reader=new FileReader();
        reader.onload=function(){
            var cona=document.getElementById("contenta");
            cona.innerHTML=this.result;
        }
    }
    reader.readAsBinaryString(file);
}
function bShow(){
    var file=document.getElementById("fileb").files[0];
    if(file){
        var reader=new FileReader();
        reader.onload=function(e){
            var conb=document.getElementById("contentb");
            conb.innerHTML=e.target.result;
        }
    }
    reader.readAsText(file);
}
</script> 
<div id="dd"> </div>
<p>图像:<input type="file" name="file" id='file' onchange='show()'/></p>
<p id='content'></p>
<p>二进制文件:<input type="file" name="file" id='filea' onchange='aShow()'/></p>
<p id='contenta'></p>
<p>文本文件:<input type="file" name="file" id='fileb' onchange='bShow()'/></p>
<p id='contentb'></p>
</body>
</html>

例子2:兼容IE的上传图片

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>     
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />     
<title>图片上传本地预览</title>     
<style type="text/css">
#preview{width:547px;height:626px;border:1px solid #000;overflow:hidden;}
#imghead {filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=image);}
input{margin-top:20px;}
</style>
<script type="text/javascript">


                //图片上传预览    IE是用了滤镜。
        function previewImage(file)
        {
          var MAXWIDTH  = 547; 
          var MAXHEIGHT = 626;
          var div = document.getElementById('preview');
          if (file.files && file.files[0])
          {
              div.innerHTML ='<img id=imghead>';
              var img = document.getElementById('imghead');
              img.onload = function(){
                var rect = clacImgZoomParam(MAXWIDTH, MAXHEIGHT, img.offsetWidth, img.offsetHeight);
                img.width  =  rect.width;
                img.height =  rect.height;
//                 img.style.marginLeft = rect.left+'px';
                img.style.marginTop = rect.top+'px';
              }
              var reader = new FileReader();
              reader.onload = function(evt){img.src = evt.target.result;}
              reader.readAsDataURL(file.files[0]);
          }
          else //兼容IE
          {
            var sFilter='filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=scale,src="';
            file.select();
            var src = document.selection.createRange().text;
            div.innerHTML = '<img id=imghead>';
            var img = document.getElementById('imghead');
            img.filters.item('DXImageTransform.Microsoft.AlphaImageLoader').src = src;
            var rect = clacImgZoomParam(MAXWIDTH, MAXHEIGHT, img.offsetWidth, img.offsetHeight);
            status =('rect:'+rect.top+','+rect.left+','+rect.width+','+rect.height);
            div.innerHTML = "<div id=divhead style='width:"+rect.width+"px;height:"+rect.height+"px;margin-top:"+rect.top+"px;"+sFilter+src+"\"'></div>";
          }
        }
        function clacImgZoomParam( maxWidth, maxHeight, width, height ){
            var param = {top:0, left:0, width:width, height:height};
            if( width>maxWidth || height>maxHeight )
            {
                rateWidth = width / maxWidth;
                rateHeight = height / maxHeight;
                
                if( rateWidth > rateHeight )
                {
                    param.width =  maxWidth;
                    param.height = Math.round(height / rateWidth);
                }else
                {
                    param.width = Math.round(width / rateHeight);
                    param.height = maxHeight;
                }
            }
            
            param.left = Math.round((maxWidth - param.width) / 2);
            param.top = Math.round((maxHeight - param.height) / 2);
            return param;
        }
</script>     
</head>     
<body>
     
    <input type="file" onchange="previewImage(this)" />  
    <div id="preview">
        <img id="imghead" src=''>
    </div>   
</body>     
</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的进度条。

<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>无标题文档</title>

</head>

<body>
<form>  
    <fieldset>  
        <legend>分度读取文件:</legend>  
        <input type="file" id="file" />  
        <input type="button" value="中断" id="Abort" />  
        <p>  
            <label>读取进度:</label><progress id="Progress" value="0" max="100"></progress>  
        </p>  
        <p id="Status"></p>  
    </fieldset>  
</form>  
<script>
    var h = {  
    init: function() {  
        var me = this;  
           
        document.getElementById('file').onchange = me.fileHandler;  
        document.getElementById('Abort').onclick = me.abortHandler;  
           
        me.status = document.getElementById('Status');  
        me.progress = document.getElementById('Progress');  
        me.percent = document.getElementById('Percent');  
           
        me.loaded = 0;  
        //每次读取1M  
        me.step = 1024 * 1024;  
        me.times = 0;  
    },  
    fileHandler: function(e) {  
        var me = h;  
           
        var file = me.file = this.files[0];  
           
        var reader = me.reader = new FileReader();  
           
        //  
        me.total = file.size;  
           
        reader.onloadstart = me.onLoadStart;  
        reader.onprogress = me.onProgress;  
        reader.onabort = me.onAbort;  
        reader.onerror = me.onerror;  
        reader.onload = me.onLoad;  
        reader.onloadend = me.onLoadEnd;  
        //读取第一块  
        me.readBlob(file, 0);  
    },  
    onLoadStart: function() {  
        var me = h;  
    },  
    onProgress: function(e) {  
        var me = h;  
           
        me.loaded += e.loaded;  
        //更新进度条  
        me.progress.value = (me.loaded / me.total) * 100;  
    },  
    onAbort: function() {  
        var me = h;  
    },  
    onError: function() {  
        var me = h;  
           
    },  
    onLoad: function() {  
        var me = h;  
   
        if(me.loaded < me.total) {  
            me.readBlob(me.loaded);  
        } else {  
            me.loaded = me.total;  
        }  
    },  
    onLoadEnd: function() {  
        var me = h;  
           
    },  
    readBlob: function(start) {  
        var me = h;  
           
        var blob,  
            file = me.file;  
           
        me.times += 1;  
           
        if(file.webkitSlice) {  
            blob = file.webkitSlice(start, start + me.step + 1);  
        } else if(file.mozSlice) {  
            blob = file.mozSlice(start, start + me.step + 1);  
        }  
           
        me.reader.readAsText(blob);  
    },  
    abortHandler: function() {  
        var me = h;  
           
        if(me.reader) {  
            me.reader.abort();  
        }  
    }  
};  
   
h.init();  
</script>
</body>
</html>
<form>
    <fieldset>
        <legend>分度读取文件:</legend>
        <input type="file" id="File" />
        <input type="button" value="中断" id="Abort" />
        <p>
            <label>读取进度:</label><progress id="Progress" value="0" max="100"></progress>
        </p>
        <p id="Status"></p>
    </fieldset>
</form>
JS代码如下:
    
var h = {
    init: function() {
        var me = this;
         
        document.getElementById('File').onchange = me.fileHandler;
        document.getElementById('Abort').onclick = me.abortHandler;
         
        me.status = document.getElementById('Status');
        me.progress = document.getElementById('Progress');
        me.percent = document.getElementById('Percent');
         
        me.loaded = 0;
        //每次读取1M
        me.step = 1024 * 1024;
        me.times = 0;
    },
    fileHandler: function(e) {
        var me = h;
         
        var file = me.file = this.files[0];
         
        var reader = me.reader = new FileReader();
         
        //
        me.total = file.size;
         
        reader.onloadstart = me.onLoadStart;
        reader.onprogress = me.onProgress;
        reader.onabort = me.onAbort;
        reader.onerror = me.onerror;
        reader.onload = me.onLoad;
        reader.onloadend = me.onLoadEnd;
        //读取第一块
        me.readBlob(file, 0);
    },
    onLoadStart: function() {
        var me = h;
    },
    onProgress: function(e) {
        var me = h;
         
        me.loaded += e.loaded;
        //更新进度条
        me.progress.value = (me.loaded / me.total) * 100;
    },
    onAbort: function() {
        var me = h;
    },
    onError: function() {
        var me = h;
         
    },
    onLoad: function() {
        var me = h;
        if(me.loaded < me.total) {
            me.readBlob(me.loaded);
        } else {
            me.loaded = me.total;
        }
    },
    onLoadEnd: function() {
        var me = h;
         
    },
    readBlob: function(start) {
        var me = h;
         
        var blob,
            file = me.file;
         
        me.times += 1;
         
        if(file.webkitSlice) {
            blob = file.webkitSlice(start, start + me.step + 1);
        } else if(file.mozSlice) {
            blob = file.mozSlice(start, start + me.step + 1);
        }
         
        me.reader.readAsText(blob);
    },
    abortHandler: function() {
        var me = h;
         
        if(me.reader) {
            me.reader.abort();
        }
    }
};
h.init();

4.预览文本文件
     这里主要用到FileReader的readAsText,对于诸如mimetype为text/plain、text/html等文件均认为是文本文件,即minetype为text开头都能在本例中预览。
     由于需要在页面上预览文本,如果使用innerHTML插入文本的话,则需要对html中一些特殊字符进行实体编码,这样才能保证正常显示文本。
    encodeHTML方法:

function encodeHTML(source) {
    return source
            .replace(/&/g, '&')
            .replace(/</g, '<')
            .replace(/>/g, '>')
            .replace(/"/, '"')
            .replace(/'/, ''');
};
function fileSelect(e) {
    e = e || window.event;
     
    var files = e.target.files;  //FileList Objects    
    var ireg = /text\/.*/i,
        p = document.getElementById('Preview');
         
    var ul = document.getElementById('Errors');
    for(var i = 0, f; f = files[i]; i++) {
        console.log(f.type);
        if(!f.type.match(ireg)) {
            //设置错误信息
            var li = document.createElement('li');
            li.innerHTML = '<li>' + f.name +'不是文本文件.</li>';
             
            ul.appendChild(li);
             
            continue;
        }
         
        var reader = new FileReader();
         
        reader.onload = (function(file) {
            return function(e) {
                var div = document.createElement('div');
                div.className = "text"
                div.innerHTML = encodeHTML(this.result);
                 
                p.insertBefore(div, null);
            };
        })(f);
        //读取文件内容
        reader.readAsText(f);
    }
}
     
if(window.File && window.FileList && window.FileReader && window.Blob) {
    document.getElementById('Files').addEventListener('change', fileSelect, false);
} else {
    document.write('您的浏览器不支持File Api');
}

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。

function readBlob(start, end) {
    var files = document.getElementById('file').files;
     
    if(!files.length) {
        alert('请选择文件');
        return false;
    }
     
    var file = files[0],
        start = parseInt(start, 10) || 0,
        end = parseInt(end, 10) || (file.size - 1);
         
    var r = document.getElementById('range'),
        c = document.getElementById('content');
         
    var reader = new FileReader();
     
    reader.onloadend = function(e) {
        if(this.readyState == FileReader.DONE) {
            c.textContent = this.result;
            r.textContent = "Read bytes: " + (start + 1) + " - " + (end + 1) + " of " + file.size + " bytes";
        }
    };
    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');
    }
     
    reader.readAsBinaryString(blob);
};
try {
    document.getElementById('buttons').addEventListener('click', function(e) {
        if(e.target.tagName.toLowerCase() == 'button') {
            var start = e.target.getAttribute('data-start'),
                end = e.target.getAttribute('data-end');
                 
            readBlob(start, end);
        }  
    });
} catch(ex) {
    alert('something error happens!')
}


评论(0)

请先登录后再评论,如果没有账号请先注册

发表评论