HTML5中的Blob对象只是二进制数据的容器,自己并不能操做二进制,故本篇将对其操做对象FileReader进行介绍。前端
FileReader主要用于将文件内容读入内存,经过一系列异步接口,能够在主线程中访问本地文件。web
使用FileReader对象,web应用程序能够异步的读取存储在用户计算机上的文件(或者原始数据缓冲)内容,可使用File对象或者Blob对象来指定所要处理的文件或数据。后端
var reader = new FileReader();
方法定义 | 描述 |
---|---|
abort():void | 终止文件读取操做 |
readAsArrayBuffer(file):void | 异步按字节读取文件内容,结果用ArrayBuffer对象表示 |
readAsBinaryString(file):void | 异步按字节读取文件内容,结果为文件的二进制串 |
readAsDataURL(file):void | 异步读取文件内容,结果用data:url的字符串形式表示 |
readAsText(file,encoding):void | 异步按字符读取文件内容,结果用字符串形式表示 |
事件名称 | 描述 |
---|---|
onabort | 当读取操做被停止时调用 |
onerror | 当读取操做发生错误时调用 |
onload | 当读取操做成功完成时调用 |
onloadend | 当读取操做完成时调用,不论是成功仍是失败 |
onloadstart | 当读取操做将要开始以前调用 |
onprogress | 在读取数据过程当中周期性调用 |
FileReader经过异步的方式读取文件内容,结果均是经过事件回调获取,下面是一个读取本地txt文件内容的例子:数组
var input = document.getElementById("file"); //input file input.onchange = function(){ var file = this.files[0]; if(!!file){ //读取本地文件,以gbk编码方式输出 var reader = new FileReader(); reader.readAsText(file,"gbk"); reader.onload = function(){ //读取完毕后输出结果 console.log(this.result); } } }
此外咱们还能够经过注册onprogress、onerror等事件,记录文件读取进度或异常行为等等。服务器
FileReader提供了四种不一样的读取文件的方式,如:readAsArrayBuffer会将文件内容读取为ArrayBuffer对象,readAsBinaryString则将文件读取为二进制串,下面对这四种方式进行简单区分。
首先准备一张图片(6764 字节)和一个txt文本(51字节)做为测试文件:
网络
接着编写测试代码:app
var reader = new FileReader(); // 经过四种方式读取文件 //reader.readAsXXX(file); reader.onload = function(){ //查看文件输出内容 console.log(this.result); //查看文件内容字节大小 console.log(new Blob([this.result])) }
查看图片输出结果:
异步
查看txt输出结果:
ide
很明显,readAsDataURL会将文件内容进行base64编码后输出,这个很好区分。函数
此方法能够经过不一样的编码方式读取字符,咱们使用utf-8
读取
查看图片输出结果:
查看txt输出结果:
readAsText读取文件的单位是字符,故对于文本文件,只要按规定的编码方式读取便可;
而对于媒体文件(图片、音频、视频),其内部组成并非按字符排列,故采用readAsText读取,会产生乱码,同时也不是最理想的读取文件的方式
查看图片输出结果:
查看txt输出结果:
与readAsText不一样的是,readAsBinaryString函数会按字节读取文件内容。
然而诸如0101的二进制数据只能被机器识别,若想对外可见,仍是须要进行一次编码,而readAsBinaryString的结果就是读取二进制并编码后的内容。
尽管readAsBinaryString方法能够按字节读取文件,但因为读取后的内容被编码为字符,大小会受到影响,故不适合直接传输,也不推荐使用。
如:测试的图片文件原大小为6764 字节,而经过readAsBinaryString读取后,内容被扩充到10092个字节
查看图片输出结果:
查看txt输出结果:
与readAsBinaryString相似,readAsArrayBuffer方法会按字节读取文件内容,并转换为ArrayBuffer对象。
咱们能够关注下文件读取后大小,与原文件大小一致。
这也就是readAsArrayBuffer与readAsBinaryString方法的区别,readAsArrayBuffer读取文件后,会在内存中建立一个ArrayBuffer对象(二进制缓冲区),将二进制数据存放在其中。经过此方式,咱们能够直接在网络中传输二进制内容。
好了说这么多,那ArrayBuffer究竟是个毛?
关于ArrayBuffer对象牵涉的知识点比较多,彻底能够单开一篇细说,在此只要简单理解为存放了一段二进制数据的内存空间便可。
而自己ArrayBuffer中的内容对外是不可见的,若要查看其中的内容,就要引入另外一个概念:类型化数组
咱们能够尝试查看下刚刚经过readAsArrayBuffer方法读取的图片文件内容:
能够看到,整个图片文件的6764个字节,被分别存储在长度为6764的数组中,而数组中每个元素的值,为当前字节的十进制数值。
关于ArrayBuffer和类型化数组的概念在此不作深刻解释,以后会再写一篇单独讨论。
说了这么多,最后仍是要落实到FileReader能解决什么问题,下面经过几个例子说明:
咱们知道,img的src属性或background的url属性,能够经过被赋值为图片网络地址或base64的方式显示图片。
在文件上传中,咱们通常会先将本地文件上传到服务器,上传成功后,由后台返回图片的网络地址再在前端显示。
经过FileReader的readAsDataURL方法,咱们能够不通过后台,直接将本地图片显示在页面上。这样作能够减小先后端频繁的交互过程,减小服务器端无用的图片资源,代码以下:
var input = document.getElementById("file"); // input file input.onchange = function(){ var file = this.files[0]; if(!!file){ var reader = new FileReader(); // 图片文件转换为base64 reader.readAsDataURL(file); reader.onload = function(){ // 显示图片 document.getElementById("file_img").src = this.result; } } }
运行效果以下:
对于图片上传,咱们也能够先将图片转换为base64进行传输,此时因为传输的图片内容就是一段字符串,故上传接口能够当作普通post接口处理,当图片传输到后台后,能够在转换为文件实体存储。
固然,考虑到base64转换效率及其自己的大小,本方法仍是适合于上传内容简单或所占内存较小的文件。
HTML5体系的创建引入了一大堆新的东西,基于XHR2,咱们能够直接上传或下载二进制内容,无需像以往同样经过form标签由后端拉取二进制内容。
简单整理下上传逻辑:
一、经过input[type="file"]标签获取本地文件File对象
二、经过FileReader的readAsArrayBuffer方法将File对象转换为ArrayBuffer
三、建立xhr对象,配置请求信息
四、经过xhr.sendAsBinary直接将文件的ArrayBuffer内容装填至post body后发送
代码实现以下:
var input = document.getElementById("file"); // input file input.onchange = function(){ var file = this.files[0]; if(!!file){ var reader = new FileReader(); reader.readAsArrayBuffer(file); reader.onload = function(){ var binary = this.result; upload(binary); } } } //文件上传 function upload(binary){ var xhr = new XMLHttpRequest(); xhr.open("POST", "http://xxxx/opload"); xhr.overrideMimeType("application/octet-stream"); //直接发送二进制数据 if(xhr.sendAsBinary){ xhr.sendAsBinary(binary); }else{ xhr.send(binary); } // 监听变化 xhr.onreadystatechange = function(e){ if(xhr.readyState===4){ if(xhr.status===200){ // 响应成功 } } } }
本篇主要介绍了FileReader对象的属性及应用场景,有了FileReader,咱们能够将本地文件读取到内存中。文中咱们提到了ArrayBuffer和类型化数组的概念,这使得咱们能够在内存中进一步操做二进制数据,关于这部份内容,会在以后的博客中进行概括。
[1] MDN_FileReader
[2] Unicode 和 UTF-8 有何区别