一、FileReader介绍

HTML5定义了FileReader作为文件API的重要成员用于读取文件,根据W3C的定义,FileReader接口提供了读取文件的方法和包含读取结果的事件模型。

FileReader的使用方式非常简单,可以按照如下步骤创建FileReader对象并调用其方法:

1.检测浏览器对FileReader的支持

if(window.FileReader) {
    var fr = new FileReader();
    // add your code here
}
else {
    alert("Not supported by your browser!");
}



//判断浏览器是否支持FileReader
if (typeof FileReader == "undefined") {
    document.write("您的浏览器不支持FileReader");
} else {
    document.write("您的浏览器支持FileReader");
}

FileReader是一种异步文件读取机制,结合input:file可以很方便的读取本地文件。



input:file

在介绍FileReader之前,先简单介绍input的file类型。

<input type="file" id="file">

input的file类型会渲染为一个按钮和一段文字。点击按钮可打开文件选择窗口,文字表示对文件的描述(大部分情况下为文件名);file类型的input会有files属性,保存着文件的相关信息。

document.querySelector('#file').addEventListener('change',(fileChoosed) => {
    console.log('fileChoosed', fileChoosed.target.files)    
})

点击按钮上传一个文件后,在控制台打印上传的文件信息,如下:

HTML5之FileReader的使用_sed

 

可以发现文件信息是一个json对象,由传入的file对象组成。每个file对象(即每个上传文件)包含以下属性:

lastModified:数值,表示最近一次修改时间的毫秒数;
lastModifiedDate:对象,表示最近一次修改时间的Date对象;
name:本地文件系统中的文件名;
size:文件的字节大小;
type:字符串,文件的MIME类型;

webkitRelativePath:此处为空;当在input上加上webkitdirectory属性时,用户可选择文件夹,此时webkitRelativePath表示文件夹中文件的相对路径。

<input type="file" id="file" webkitdirectory>



二、FileReader简单使用

FileReader 的实例拥有 4 个方法,其中 3 个用以读取文件,另一个用来中断读取。下面的表格列出了这些方法以及他们的参数和功能,需要注意的是 ,无论读取成功或失败,方法并不会返回读取结果,这一结果存储在 result属性中。

HTML5之FileReader的使用_sed_02

以上file对象只获取到了对文件的描述信息,但没有获得文件中的数据。我们可以通过html5提供的FileReader读取到文件中的数据。

首先创建一个FileReader实例:

const reader = new FileReader();

FileReader提供了如下方法:



readAsArrayBuffer(file)

按字节读取文件内容,结果用ArrayBuffer对象表示



readAsBinaryString(file)

按字节读取文件内容,结果为文件的二进制串



readAsDataURL(file)

读取文件内容,结果用data:url的字符串形式表示



readAsText(file,encoding)

按字符读取文件内容,结果用字符串形式表示



abort()

终止文件读取操作

 

readAsDataURL和readAsText较为常用,这里只对这两者进行说明。

readAsDataURL会将文件内容进行base64编码后输出:

document.querySelector('#file').addEventListener('change',(fileChoosed) => {
   const reader = new FileReader();
   reader.readAsDataURL(fileChoosed.target.files[0]);//发起异步请求
   reader.onload = function(readRes){
       console.log('加载完成', readRes.target.result)
   }          
})

控制台为当前所传文件的base64编码表示。由于媒体文件的src属性,可以通过采用网络地址或base64的方式显示,因此我们可以利用readAsDataURL实现对图片的预览。
如下,只需将读取的结果赋给图片的src属性,即可预览图片:

<input type="file" id="file" />
<img src="" id="imgPreview">
document.querySelector('#file').addEventListener('change',(fileChoosed) => {
    const reader = new FileReader();
    reader.readAsDataURL(fileChoosed.target.files[0]);//发起异步请求
    reader.onload = function(readRes){
        document.querySelector('#imgPreview').src = readRes.target.result
    }           
})

readAsText可按指定编码方式读取文件,但读取文件的单位是字符,故对于文本文件,只要按规定的编码方式读取即可;而对于媒体文件(图片、音频、视频),其内部组成并不是按字符排列,故采用readAsText读取,会产生乱码。



FileReader事件:

FileReader 包含了一套完整的事件模型,用于捕获读取文件时的状态,下面这个表格归纳了这些事件。

HTML5之FileReader的使用_读取文件_03

onloadstart 当读取操作开始时调用
onprogress 在读取数据过程中周期性调用
onabort 当读取操作被中止时调用
onerror 当读取操作发生错误时调用
onload 当读取操作成功完成时调用
onloadend 当读取操作完成时调用,无论成功,失败或取消

注释:

每过50ms左右,就会触发一次progress事件,对于较大的文件可以利用progress实现进度条;
由于种种原因无法读取文件时,会触发error事件。触发error事件时,相关信息保存在FileReader对象的error属性中,这个属性将保存一个对象,此对象只有一个属性code,即错误码。1表示未找到文件,2表示安全性错误,3表示读取中断,4表示文件不可读,5表示编码错误。
示例:

<input type="file" id="file" />
document.querySelector('#file').addEventListener('change',(fileChoosed) => {
    const reader = new FileReader();
    reader.readAsText(fileChoosed.target.files[0],'utf-8');//发起异步请求
    reader.onloadstart = function(readRes){
    	// 文件大于500kb则取消加载
        if(readRes.total > 1024*500) {            
            reader.abort()
        } else {
            console.log("开始加载")
        }
    }
    reader.onabort = function (readRes) {
        console.log('加载已取消')
    }
    reader.onprogress = function(readRes){
        console.log("加载中", `${(readRes.loaded / readRes.total).toFixed(2)*100}/100`)
    }
    reader.onload = function(readRes){
        console.log('加载成功')
    }
    reader.onloadend= function(readRes){
        console.log("加载结束")
    }            
})

文件一旦开始读取,无论成功或失败,实例的 result 属性都会被填充。如果读取失败,则 result 的值为 null ,否则即是读取的结果,绝大多数的程序都会在成功读取文件的时候,抓取这个值。

fr.onload = function() {
    this.result;
};

 

 



下面是部分实例代码:

h5使用FileReader读取本地图片文件并显示到浏览器

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>h5使用FileReader读取本地图片文件并显示到浏览器-赵克立博客</title>
    <meta name="keywords" content="h5使用FileReader读取本地图片文件并显示到浏览器-赵克立博客" />
    <meta name="description" content="h5使用FileReader读取本地图片文件并显示到浏览器-赵克立博客" />
</head>
<body>
    <input type="file" id="file_input" name="img" />
    <div id="showimg">
    </div>
    <script type="text/javascript">
    ! function(a, b) {
        var showimg = document.getElementById("showimg");
        var imginput = document.getElementById("file_input");
        if (typeof FileReader === 'undefined') {
            showimg.innerHTML = "抱歉,你的浏览器不支持 FileReader";
            imginput.setAttribute('disabled', 'disabled');
        } else {
            imginput.addEventListener('change', function() {
                var file = this.files[0];
                if (!/image\/\w+/.test(file.type)) {
                    alert("请确保文件为图像类型");
                    return false;
                }
                var reader = new FileReader();
                reader.readAsDataURL(file);
                reader.onload = function(e) {
                    showimg.innerHTML = '<img src="' + this.result + '" alt=""/>'
                }
            }, false);
        }
    }(window);
    </script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8"/>
  <title></title>
  <script>
    window.onload = function () {
      var oFile = document.getElementById("file");
      oFile.onchange = function(){
        //获取第1个文件
        var file = oFile.files[0];
        //将图片转换为Base64格式
        var reader = new FileReader();
        reader.readAsDataURL(file);
        reader.onload = function(){
          //添加图片到页面中
          var oImg = document.createElement("img");
          oImg.src = this.result;
          document.body.appendChild(oImg);
        };
      };
    }
  </script>
</head>
<body>
  <input id="file" type="file" /><br/>
</body>
</html>

 

 

 

 



读取本地文本文件并显示.html

<!DOCTYPE html>
<html>
<head>
 <meta charset="UTF-8">
 <title>读取本地文件文件并显示</title>
</head>
<body>
 
<script>
function show()
{
    var reader = new FileReader();
    reader.onload = function() 
    {
        //alert(this.result)
        story.value=this.result
    }
    var f = document.getElementById("filePicker").files[0];
    reader.readAsText(f);
}
</script>
 
<input type="file" name="file" id="filePicker" onchange="show()"  />
<br>
 
<textarea id="story" name="story" rows="15" cols="60">
</textarea>
 
</body>
</html>

HTML5之FileReader的使用_sed_04

HTML5之FileReader的使用_html_05

 



读取本地图片文件并显示.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
    <title>读取本地图片文件并显示</title>
</head>
<body>
    <!-- multiple 一个文件选择框可以同时选择多个文件
      <input type="file" id="selectFiles" onchange="dealSelectFiles()" multiple webkitdirectory> 
    --> 
    <input type="file" id="selectFiles" onchange="dealSelectFiles()" >
    <canvas id="myCanvas" width=1440 height=900></canvas>
  
    <script>
        var imgPosX = 0;
        var imgWidth = 256;
        function dealSelectFiles(){
            // get select files.
            var selectFiles = document.getElementById("selectFiles").files;
  
            for(var file of selectFiles){
                console.log(file.webkitRelativePath);
                // read file content.
                var reader = new FileReader();
                reader.readAsDataURL(file);
                reader.onloadend = function(){
                    // deal data.
                    var img = new Image();
                    // after loader, result storage the file content result.
                    img.src = this.result;  
                    img.onload = function(){
                        var myCanvas = document.getElementById("myCanvas");
                        var cxt = myCanvas.getContext('2d');
                        cxt.drawImage(img, imgPosX, 0);
                        imgPosX += imgWidth;
                    }
                }
            }
        }
    </script>
</body>
</html>

HTML5之FileReader的使用_读取文件_06

HTML5之FileReader的使用_html_07

 

拖拽

拖拽是另一种常见的文件访问场景,这种方式通过dataTransfer的对象来获得拖拽文件列表。同样可以支持多文件拖拽。

下面给出拖拽本地文本文件并在textarea中显示的源码:



拖拽本地文本文件并显示例.html

<!DOCTYPE html> 
<html> 
<head> 
<meta charset="UTF-8">
<title>拖拽本地文本文件并显示</title>
 <style>
        .box {
            width: 400px;
            height: 400px;
            border: 1px solid #000;
            margin: 100px auto;
            box-shadow: 0 0 10px 5px rgba(0,0,0,.8);
            border-radius: 10px;
            line-height: 400px;
            text-align: center;
            font-size: 30px;
            font-weight: 700;
            text-shadow:0 0 5px;
            transition:all 1s;
        }
      .box #entity{
            width: 100%;
            height: 100%;
       }
</style>
 </head>
 <body>
 <div class="box">拖拽外部文件至此</div>
 <script>
     // 需求:拖拽外部文件到当前页面进行解析
     // 获取目标元素
    var box = document.querySelector('.box');
  
    //解决一旦拖拽外部文件就覆盖掉当前页面的问题
    //  解决:给document绑定drop事件 
    //  drop事件默认触发不了,需要在dragover事件里面阻止默认事件
    document.ondrop = function(e){
        e.preventDefault();
    }
    // 这个阻止默认事件是为了让drop事件得以触发
    document.ondragover = function(e){
        e.preventDefault();
    }
 
    box.ondragenter = function(){
        box.style.boxShadow = '0 0 10px 5px rgba(255,0,0,.8)';
    }
 
    box.ondrop = function(e){
        // console.log(e);
        // 得到拖拽过来的文件
        var dataFile = e.dataTransfer.files[0];
        // FileReader实例化
        var fr = new FileReader();
        // 异步读取文件
        fr.readAsText(dataFile);
        // 读取完毕之后执行
        fr.onload = function(){
            // 获取得到的结果
            var data = fr.result;
 
            var ta = document.createElement('textarea');
            ta.value = data;
            ta.id='entity';
            box.innerHTML = '';
            box.appendChild(ta);
 
        }
    }
</script> 
</body> 
</html>

HTML5之FileReader的使用_html5_08

HTML5之FileReader的使用_sed_09

 



拖拽本地图片文件并显示.html

<!DOCTYPE html>
 <html>
     <head>
         <meta charset="UTF-8">
         <title>拖拽本地图片文件并显示</title>
         <style type="text/css">
             #area{width:100%;height:200px; line-height: 200px; text-align: center; border: 1px solid #DDDDDD;}
             #prev{width:100%;min-height: 400px; border: 1px solid #FF0000;}
         </style>
     </head>
     <body>
         <div id="area">将图片拖放到该区域</div>
         <h1>图片预览</h1>
         <hr />
         <div id="prev"></div>
     </body>
 
   <script>
     window.onload = function(){
         var oArea = document.getElementById("area");
         var oPrev = document.getElementById("prev");
         
         oArea.ondragenter = function(){
             oArea.innerHTML = "请释放鼠标";
         }
         oArea.ondragleave = function(){
             oArea.innerHTML = "将图片拖放到该区域";
         }
         oArea.ondragover = function(ev){
             ev.preventDefault();
         }
         oArea.ondrop = function(ev){
             ev.preventDefault();
             var files = ev.dataTransfer.files;
             for(var i = 0 , len = files.length;i<len;i++){
                 var file = files[i];
                 var reader = new FileReader();
                 reader.readAsDataURL(file);
                 (function(reader){
                     reader.onload = function(){
                         var oImg = document.createElement("img");
                         oImg.src = this.result;
                         oPrev.appendChild(oImg);
                     }
                 })(reader);
                 
             }
             
         }
         
     }
   </script>
</html>

HTML5之FileReader的使用_读取文件_10

HTML5之FileReader的使用_读取文件_11