web前端-在迷惘中的探索HTML5(三)文件操作FileReader

简介

在HTML5中,文件选择标签file增加了如下两个属性:

  • multiple:设定当前元素可以选取多个文件。
  • accept:设定当前选择器可以选择的MIME类型或后缀名。
<input type="file" multiple name="" id="myfilePhoto" value="" accept="image/jpg, image/png">

于此同时,其出现了FileReader对象,使用FileReader对象,web应用程序可以异步的读取存储在用户计算机上的文件(或者原始数据缓冲)内容,可以使用File对象或者Blob对象来指定所要处理的文件或数据。

FileReader:是window对象的一个构造函数,用于读取文件选择标签选择的File的Dom对象。即用来把文件选择的信息读入内存,并且读取文件中的数据。其接口提供了一个异步API,使用该API可以在浏览器主线程中异步访问文件系统,读取文件中的数据。为了安全FileReader可以读取表单上已经选择的文件,不能读取本地文件,它以二进制信息的方式读取表单文件:主要用于大文件的信息读取。

特点:

  1. 读取后,二进制信息在浏览器内存中,批量的向服务器进行传输。
  1. 一般要配合后台程序,第三方插件共同完成
  2. 断点下载和断点上传

使用介绍

创建FileReader对象

想要创建一个FileReader对象,很简单,如下:

var fr = new FileReader();
FileReader的状态常量:

|常量名 | 值 | 描述
|-
|EMPTY | 0 | 还没有加载任何数据.
|LOADING | 1 | 数据正在被加载.
|DONE | 2 | 已完成全部的读取请求.

FileReader接口的方法

FileReader接口有5个方法,其中4个用来读取文件,另一个用来中断读取。无论读取成功或失败,方法并不会直接返回读取结果,这一结果存储在result属性中。

FileReader接口的方法:

|方法名 | 参数 | 描述
|-
|readAsArrayBuffer | file | 将文件读取为一个ArrayBuffer对象以表示所读取文件的内容.
|readAsBinaryString | file | 将文件读取为二进制编码
|readAsText | file,[encoding] | 将文件读取为文本
|readAsDataURL | file | 将文件读取为DataURL,读取的内容是加密以后的本地文件路径
|abort | (none) | 终端读取操作

FileReader的属性:

|属性名 | 类型 | 描述
|-
|error | DOMError | 在读取文件时发生的错误. 只读.
|readyState | unsigned short | 表明FileReader对象的当前状态. 值为State constants中的一个. 只读
|result | jsval | 读取到的文件内容.这个属性只在读取操作完成之后才有效,并且数据的格式取决于读取操作是由哪个方法发起的. 只读.

FileReader接口事件

FileReader接口包含了一套完整的事件模型,用于捕获读取文件时的状态。

FileReader接口的事件:

|事件 | 描述
|-
|onabort | 中断
|onerror | 出错
|onloadstart | 开始
|onprogress | 正在读取
|onload | 成功读取
|onloadend | 读取完成,无论成功失败

实例说明一切:

讲完这些大家其实还是不知道怎么用,于是,实例来说明一切:

<!-- multiple多个文件 -->
<input type="file" multiple name="" id="myfilePhoto" value="" accept="image/jpg, image/png">
<ul class="fileUl"></ul>
<script>
    document.getElementById('myfilePhoto').addEventListener("change",function(){
        var inputFile = document.getElementById('myfilePhoto');
        for(var i = 0; i<inputFile.files.length ;i++){
            var fr = new FileReader(); // 这个FileReader应该对应于每一个读取的文件都需要重新new一个
            var files = inputFile.files[i]; // files可以获取当前文件输入框中选择的所有文件,返回列表
            fr.readAsDataURL(files); // 读取的内容是加密以后的本地文件路径
            fr.onload = function(e){ // 数据读取完成时触发onload对应的响应函数
                // e.target是FileReader等同于fr
                var ulLi = document.createElement('li');
                var ulLiA = document.createElement('a');
                var ulLiimg = document.createElement('img');
                ulLiimg.src = e.target.result
                ulLiA.appendChild(ulLiimg);
                ulLi.appendChild(ulLiA);
                console.log(document.getElementsByClassName('fileUl'))
                document.getElementsByClassName('fileUl')[0].appendChild(ulLi)
            }       
        }
    });
</script>
<script>
    function updateSize() {
        var nBytes = 0;
        var oFiles = document.getElementById("uploadInput").files;
        var nFiles = oFiles.length;
        for (var nFileId = 0; nFileId < nFiles; nFileId++) {
            nBytes += oFiles[nFileId].size;
        }
        var sOutput = nBytes + " bytes";
        var aMultiples = ["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"];
        var nMultiple = 0, nApprox = nBytes / 1024;

        for ( ; nApprox > 1; nApprox /= 1024, nMultiple++) {
            sOutput = nApprox.toFixed(3) + " " + aMultiples[nMultiple] + " (" + nBytes + " bytes)";
        }

        document.getElementById("fileNum").innerHTML = nFiles;
        document.getElementById("fileSize").innerHTML = sOutput;
    }
</script>
<p>
    <input id="uploadInput" type="file" name="myFiles" onchange="updateSize();" multiple>
    选择的文件数:<span id="fileNum">0</span>
    总共大小:<span id="fileSize">0</span>
</p>

注意:在遍历时把 var fileReader = new FileReader(); 放到了循环之外,会导致了 Uncaught InvalidStateError: Failed to execute 'readAsDataURL' on 'FileReader': The object is already busy reading Blobs.错误,这个FileReader应该对应于每一个读取的文件都需要重新new一个。
onload只在所有数据读取成功完成时触发,并且结果也只在onload之后才有。
问题解释:因为你每次循环如果只new了一次相当与你只创建一个fileReader对象,可是我们每次循环时,拿到的文件信息却是不同的,这就好比你雇了一个员工,要求他同时去打扫卫生间又打扫办公室又去浇花,他只能先干完一件才能去干另一件,所以它就会给你报错:The object is already busy reading Blobs.对象已经在忙着阅读Blobs-即忙着处理不可变的类似文件对象的原始数据。你一定会疑问我是for循环一次完成了啊?你别忘了fr.onload是一个异步的,你for一次完成,但是处理信息并没有完成,这就是你指挥员工命令已完成,但是,员工干活却还在干,因为干活也是要时间的。

FileReader接口的使用

实例结束再来个大点案例:

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <script type="text/javascript">  
        var result=document.getElementById("result");  
        var file=document.getElementById("file");  
          
        //判断浏览器是否支持FileReader接口  
        if(typeof FileReader == 'undefined'){  
            result.InnerHTML="<p>你的浏览器不支持FileReader接口!</p>";  
            //使选择控件不可操作  
            file.setAttribute("disabled","disabled");  
        }  
          
        function readAsDataURL(){  
            //检验是否为图像文件  
            var file = document.getElementById("file").files[0];  
            if(!/image\/\w+/.test(file.type)){  
                alert("看清楚,这个需要图片!");  
                return false;  
            }  
            var reader = new FileReader();  
            //将文件以Data URL形式读入页面  
            reader.readAsDataURL(file);  
            reader.onload=function(e){  
                var result=document.getElementById("result");  
                //显示文件  
                result.innerHTML='![](' + this.result +')';  
            }  
        }  
          
        function readAsBinaryString(){  
            var file = document.getElementById("file").files[0];  
            var reader = new FileReader();  
            //将文件以二进制形式读入页面  
            reader.readAsBinaryString(file);  
            reader.onload=function(f){  
                var result=document.getElementById("result");  
                //显示文件  
                result.innerHTML=this.result;  
            }  
        }  
          
        function readAsText(){  
            var file = document.getElementById("file").files[0];  
            var reader = new FileReader();  
            //将文件以文本形式读入页面  
            reader.readAsText(file);  
            reader.onload=function(f){  
                var result=document.getElementById("result");  
                //显示文件  
                result.innerHTML=this.result;  
            }  
        }  
    </script>  
    <p>  
        <label>请选择一个文件:</label>  
        <input type="file" id="file" />  
        <input type="button" value="读取图像" onclick="readAsDataURL()" />  
        <input type="button" value="读取二进制数据" onclick="readAsBinaryString()" />  
        <input type="button" value="读取文本文件" onclick="readAsText()" />  
    </p>  
    <div id="result" name="result"></div>
</body>
</html>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容