HTML5中的文件读取---File API

1.简介

在Html5中提供了一种通过File API规范与本地文件进行交互的标准方法。在使用 File API 在向服务器发送图片的过程中可以创建图片的缩略图预览,也可以允许应用程序在用户离线时保存文件引用。另外,您可以使用客户端逻辑来验证上传内容的 type 与其文件扩展名是否匹配,或者限制上传内容的大小。
该规范通过“本地”文件系统提供了多种文件访问接口:

1.1 FileList 对象

filelist对象是针对表单的file控件,当用户利用file控件选取文件以后,这个控件的files属性就是filelist对象。

//使用多选控件
<input type='file' id="file-test" multiple />
<script>
    document.getElementById('file-test').onchange = function() {
      console.log(this.files);
    };
</script>
image.png

注:除了file控件以外,采用拖放的方式,也可以得到filelist对象。一般情况下,filelist对象只能被动的读取,不可以手动构造,只有在user主动触发(选取或拖拽)了文件读取的行为,javascript才会访问到filelist。

1.2 File对象

在filelist对象中就包括了file对象,file对象含有以下的属性:

name: 文件名,只读属性;
size: 文件大小,单位为字节,只读属性;
type: 文件的MIME类型,若是分辨不出类型,则为空字符串,只读属性;
lastModified:文件的上次修改时间,格式为时间戳;
lastModifiedDate:文件上次修改时间,格式为Date对象实例。

如下图所示:


image.png

1.3 Blob对象

Blob(Binary Large Object)对象代表了一段二进制数据,提供了一系列操作接口,其他二进制数据的API(比如File对象),都是建立在Blob对象基础上的,继承了它的属性和方法。
生成Blob对象有两种方法:一种是使用Blob构造函数,另一中是对现有的Blob对象使用slice方法切出一部分。

1.4 FileReader

FileReader对象用于读取文件,他的参数是file对象或blob对象。对于不同类型的文件,FileReader提供了不同的读取方法:

  • readerAsText(blob|File,opt_encoding) :
    返回文本字符串,默认情况下,文本编码格式是UTF-8,可以通过可选参数指定其他编码格式的文本。
  • readerAsDataURL(Blob|File) :
    返回一个基于Base64编码的data-uri对象(可用于<img>标签中的src属性,从而达到图片预览的效果)。
  • readerAsArrayBuffer(Blob|File) :
    返回一个ArrayBuffer对象。

FileReader对象采用异步方式读取文件,可以为一系列的事件指定回调函数。

  • onabort() 方法 :读取中段或者调用reader.abort()方法时触发。
  • onerror() 方法 :读取出错时触发。
  • onload() 方法 :读取成功后触发。
  • onloadend() 方法 :读取完成后触发,不管是否成功。触发顺序排在onload或onerror后面。
  • onloadstart() 方法 :读取将要开始时触发。
  • onprogress() 方法 :读取过程中周期性触发(一般可用于获取文件的读取进度)。

1.5 createObjectURL 方法

调用URL对象的createObjectURL方法,传入一个File对象或者Blob对象,能生成一个链接。这个URL可以放置于任何通常可以放置URL的地方,比如<img>标签的src属性。需注意的是即使是同样的二进制数据,每调用一次URL.createObjectURL方法。就会得到一个不一样的URL。

var URL = window.URL || window.webkitURL || window.mozURL ;
var SRC = URL.createObjectURL(file);

1.6 onprogress 事件

想要上传图片的时候显示进度条,在HTML5中提供了onprogress事件。onprogress事件可以作用于<video>或<audio>标签中,作为其状态回调函数的作用。也可以作为XMLHttpRequest的指定事件,XMLHttpRequest对象在传递数据的时候,提供了一个progress事件,用于返回进度信息。它分为 上传 和 下载 两种情况:

  • 下载的 progress 事件属于 XMLHttpRequest 对象
  • 上传的 progress 事件属于 XMLHttpRequest.upload 对象

当上传或者下载时,会频繁调用该方法。该方法接受一个事件参数event,其中event.total是需要传输的总字节,event.loaded是已经传输的字节。如果event.lengthComputable 不为真,则event.total等于0。
示例代码:

<body>
    <input type="file" id="file">
    <div class="progress">
        <div></div>
    </div>
    <button onclick="ajaxUpload()">上传</button>
    <script>
        function ajaxUpload() {
            var file = $('#file').get(0).files[0];
            var formdata = new FormData();
            formdata.append('file', file);
            $.ajax({
                url: 'test_progress.php',
                type: 'post',
                dataType: 'json',
                data: formdata,//这里上传的数据使用了formData 对象
                processData: false,  //必须false才会自动加上正确的Content-Type 
                contentType: false,  //必须设置
               //这里我们先拿到jQuery产生的 XMLHttpRequest对象,为其增加 progress 事件绑定,然后再返回交给ajax使用.
                xhr: () => {
                    var xhr = new XMLHttpRequest();
                    xhr.upload.onprogress = (evt) => {
                        console.log(evt);
                        var progressWidth = (evt.loaded / evt.total) * 100 + '%';
                        $('.progress > div').css('width', progressWidth);
                    }
                    return xhr;
                }
            })
        }
    </script>
</body>

2.检查环境

在编写前请先检查您当前的浏览器是否支持File API:

if(window.File &&window.FileReader &&window.FileList &&window.Blob) {
    alert( "Success! The File APIs are fully supported in this browser")
}else{ 
     alert('The File APIs are not fully supported in this browser.'); 
 }

3.选取文件

3.1 通过表单输入进行选取文件

选取文件最常用的方法就死使用标准的<input type="file">元素,JS会返回选定的File对象的列表,下面的示例是使用“multiple”属性实现同时选定多个文件:

  <div style="margin:0 auto;width:400px;height:200px;border:2px dashed pink">
    <input type="file" id="filetest" name="filetest" multiple />
    <output id="filelist"></output>  
  </div> 
  <script>
    function handleFileSelect(event){
      var files = event.target.files;
      var output = [];
      var i,f;
      for(i=0;f=files[i];i++){
        output.push('<li><strong>',f.name,'</strong>','-',f.size, 'bytes,last modified:',f.lastModifiedDate,'</li>');
      }
      document.getElementById("filelist").innerHTML = '<ul>'+output.join('')+'</ul>';
      
    }
    document.getElementById("filetest").addEventListener('change',handleFileSelect,false);
  </script>
image.png

3.2 通过拖拽选取文件并显示缩略图

该方法是在本地将文件从桌面拖放到浏览器进行选取,并显示图片的缩略图,具体示例如下:

<style>
   .thumb {
      height: 80px;
      border: 1px solid #eee;
      margin: 10px 5px 0 0;
    }
</style>
<body>
  <div style="width: 320px;margin: 0 auto;border:2px solid skyblue;padding:10px;">
    <div id="drop_zone" style="border:2px dashed pink;color:#bbb;text-align: center;line-height:76px;">Drop files here</div>
    <output id="list"></output>
  </div>
  <script>
    $(document).ready(function() {
      function handleFileSelect(evt) {
        evt.stopPropagation();
        evt.preventDefault();
        var files = evt.dataTransfer.files; // 拖拽选取时,FileList 对象格式.
        var i,f;
        for (i = 0; f = files[i]; i++) {
          // 匹配图片格式
          if (!f.type.match('image.*')) {
            continue;
          }
          var reader = new FileReader(); //读取文件信息
          // 捕获文件信息的闭包
          reader.onload = (function(theFile) {
            return function(e) {
              // 显示缩略图
              var span = document.createElement('span');
              span.innerHTML = ['<img class="thumb" src="', e.target.result,
                                '" title="', escape(theFile.name), '"/>'].join('');
              document.getElementById('list').insertBefore(span, null);
            };
          })(f);

          // 以URL的形式读入图像文件。
          reader.readAsDataURL(f);
        }
      }
      function handleDragOver(evt) {
        evt.stopPropagation();
        evt.preventDefault();
        evt.dataTransfer.dropEffect = 'copy'; 
      }
      // 设置dnd时间侦听器。
      var dropZone = document.getElementById('drop_zone');
      dropZone.addEventListener('dragover', handleDragOver, false);
      dropZone.addEventListener('drop', handleFileSelect, false);
  })
</script>

示例显示结果如下:


image.png

3.2 监听上传进度

在HTML5中,提供了一个FormData对象,能关于模拟一个原始的表单格式的数据,在之前的表单数据传输中,必须要用form标签将要传输的数据包裹起来了,按照规定的格式与后台传输,HTML5中的FormData对象就模拟这种格式,将form表单元素的value值与对应的name属性结合起来,组成一个querystring字符串。下面示例结合FormData实现通过onprogress事件监控读取状态,并以进度条的形式显示出来。
示例代码如下:

      <div style="text-align: center; padding-top: 50px">
            <input type="file" id="avatarfile" accept="image/png, image/jpeg, image/jpg, video/*"/>
            <button onclick="to_upload_file()">上传文件</button>
            <br>
            <div style="text-align: left;margin-top: 15px;display: inline-block;width: 300px; height: 20px; border: 1px solid #44A1F8; border-radius: 2px;position: relative">
                <div id="progress_bar" style="display: inline-block; width: 0px; height: 20px;background-color: #64B587"></div>
                <div style="text-align: center;width: 300px;position: absolute; top: 0; font-size:16px; color: #413F43">
                    <div id="loading-percent">
                        上传进度0%
                    </div>
                </div>  
            </div>
        </div>
        <script>
            function to_upload_file(){
                var fileObj = document.getElementById("avatarfile").files[0]
                if(fileObj){
                    var formContent = new FormData();
                    formContent.append("file", fileObj);
                    var xhr = new XMLHttpRequest();
                    xhr.upload.onprogress = (e)=>{
                      var progress_bar = document.getElementById("progress_bar");
                      var loadingPercent = document.getElementById("loading-percent");
                      if(e.lengthComputable){
                        var loading = Math.round(e.loaded / e.total * 100);
                      }
                      if(loading === 100){
                        loadingPercent.innerHTML = "上传成功^_^";
                      }else{
                        loadingPercent.innerHTML = "上传进度"+loading+"%"
                      }  
                      progress_bar.style.width = String(loading * 3) + "px";
                    }; // 监听上传进度
                    xhr.upload.onload = (e)=>{console.log("Success !", e)}; // 上传成功后的回调函数
                    xhr.upload.onerror =  (e)=>{console.log("Failed", e)}; // 上传失败后的回调函数
                    xhr.open("POST", "http://127.0.0.1/upload_test.php", true);
                    xhr.send(formContent);
                }else{
                    alert("当前无上传文件,请先选择文件后再上传")
                }
            }
        </script>
参考文件:

https://www.jianshu.com/p/b3e986fb1237
http://www.w3.org/TR/file-upload

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容