最近接手了一个项目,接触到一些对文件操做的业务.因此在这边整理一下平常用到的处理方式,当学习笔记吧,有不对的地方,欢迎指正哈javascript
首先咱们来看一下 FileReader
这个万能的对象, 就如同它的名字同样,就是个文件读取器,
之因此说它是个万能的对象是由于它能够读取任意格式的内容,最近我尝试过用 FileReader 读取过 psd
, ppt
, 各类图片等等.
虽然不少状况下,它读出来的是咱们彻底看不懂的东西.不过经过必定的转换,理论上咱们能够在浏览器里面打开任何文件类型.html
下面抄一段 MDN 的文档前端
FileReader 对象容许Web应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 File 或 Blob 对象指定要读取的文件或数据.其中File对象能够是来自用户在一个
<input>
元素上选择文件后返回的 FileList 对象,也能够来自拖放操做生成的 DataTransfer 对象,还能够是来自在一个 HTMLCanvasElement 上执行 mozGetAsFile() 方法后返回结果.java
因为是抄的,就不作详细讲解,重点是要知道你要读的文件的编码类型,而后调用对应的方法取读就能够了.这里有原文node
因为 FileReader 能够把文件读取成各类格式,因此这里能够利用这个特性,进行编码的转换,如 ArrayBuffer, Blob对象 和 字符串, base64 之间的相互转换/单向转换, 部分类型只能单向转换,是由于 FileReader 只接受 File 或 Blob 类型的数据(事实上 File 也 Blob 的一种),若是数据没法转换成指定类型,就没法用 FileReader 转换.git
const filereader = new FileReader(); const blob = new Blob(['hello file-reader'], { type: 'text/plain'}); filereader.onload = e => { console.log(e.target.result); // 输出 data:text/plain;base64,aGVsbG8gZmlsZS1yZWFkZXI= } filereader.readAsDataURL(blob);
网上传的用 Uint16Array 进行 String 和 ArrayBufer 互转的其实有编码长度的问题,我亲身体验过,用 FileReader 就能够避开这个问题.能够调用它的 readAsArrayBuffer()
和 readAsText()
方法,把指定对象读取成 ArrayBuffer 格式 或 纯文本格式的数据.github
固然 FileReader 不只仅能用在编码转换上,读取各类文件才是它主要的能力,配合 <input type="file" >、DataTransfer、Blob 等,能够把任意格式的数据读取到浏览器里面.web
上面屡次提到 Blob 对象,私觉得 Blob 也是个很是强大的对象,因此这里我以为很是有必要介绍一下,先看看 MDN 怎么说的json
Blob 对象表示一个不可变、原始数据的类文件对象.Blob 表示的不必定是JavaScript原生格式的数据.File 接口基于Blob,继承了 blob 的功能并将其扩展使其支持用户系统上的文件.
Blob 对象有个同名构造函数,该构造函数接收 2 个参数,第一个参数必须是个 Array 类型的,哪怕你只有一项,也必须用 [ ]
包着,如 ['hello file-reader']
,
第二个参数是个可选的,是个对象,有2个选项,type 和 endings,type 指定第一个参数的 MIME-Type, endings 指定第一个参数的数据格式,其可选值有 transparent(不变,默认) 和 native(随系统转换)数组
const blob = new Blob(['hello file-reader'], { type: 'text/plain'});
Blob.size 能够获取对象中所包含数据的大小(字节), Blob.type 能够获取对象所包含数据的MIME类型.若是类型未知,则该值为空字符串.
Blob.slice() 方法能够返回一个新的 Blob对象,包含了源 Blob对象中指定范围内的数据, 共接收3个参数,前两个参数和 Array.slice 的参数相似
参数1:开始索引,默认为0
参数2:截取结束索引(不包括当前值)
参数3:新Blob的MIME类型,默认为空字符串
const newBlob = blob.slice(0, 5, 'text/plain');
大文件分段上传就靠它了,配合 Blob.size 食用,口感更佳哈
经过 URL.createObjectURL(Blob对象), 能够把 Blob对象 转换成一个连接地址,该地址能够直接用在某些 DOM 的 src 或者 href 上, 从而实现前端下载或图片显示.
一个比较w神奇的用法是 阮老师的 web worker 教程 里的「同页面的 Web Worker」, 这个再配合动态插入 DOM, 是否是就能够绕开 webworker 的同源策略?
上面提到 FileReader 只能接受 Blob 格式的数据(其余格式其实也是Blob的子集), 其实 Blob 也只能经过 FileReader 读取.简直就是泡面跟火腿肠,最佳搭档啊哈
先说说 Arraybuffer 之因此要介绍它,是由于 FileReader 有个 readAsArrayBuffer() 方法,若是的被读的文件是二进制数据,那用这个方法去读应该是最合适的,读出来的数据,就是一个 Arraybuffer 对象,老规矩,看看定义:
ArrayBuffer 对象用来表示通用的、固定长度的原始二进制数据缓冲区.ArrayBuffer 不能直接操做,而是要经过类型数组对象或 DataView 对象来操做,它们会将缓冲区中的数据表示为特定的格式,并经过这些格式来读写缓冲区的内容.
Arraybuffer 也有个同名构造函数,用于建立一个指定长度的,内容所有为 0 的 ArrayBuffer 对象,构造函数接收一个参数,用来指定要建立的内容长度.如:
let ab = new ArrayBuffer(8); // 建立一个 8 字节的 ArrayBuffer
因为没法对 Arraybuffer 直接进行操做,因此咱们须要借助其余对象来操做. 全部就有了 TypedArray(类型数组对象)和 DataView.
Int8Array(); Uint8Array(); Uint8ClampedArray(); Int16Array(); Uint16Array(); Int32Array(); Uint32Array(); Float32Array(); Float64Array();
具体用法请参考 MDN: TypedArray
TypedArray 虽然不是真的数组,可是有几乎跟数组同样的 API,咱们能够像操做数组同样操做 TypedArray ,因此有了 TypedArray 咱们就能够把 ArrayBuffer 转换成 TypedArray,而后在进行读写操做,达到操做二进制的目的,下面是个例子
let arrayBuffer = new ArrayBuffer(8); console.log(arrayBuffer[0]); // undefined let uint8Array = new Uint8Array(arrayBuffer); console.log(uint8Array); // [0, 0, 0, 0, 0, 0, 0, 0] uint8Array[0] = 1; console.log(uint8Array[0]); // 1 console.log(uint8Array); // [1, 0, 0, 0, 0, 0, 0, 0]
能够看出,用 arrayBuffer[0]
的方式直接获取 ArrayBuffer 对象的内容是获取不到的,而 TypedArray 能够.
直接 console.log(arrayBuffer) 在控制台是能够看到[[Int8Array]] [[Int16Array]] [[Int32Array]] [[Uint8Array]]
4 种 TypedArray 数据,不过这应该是浏览器为了方便开发者观察数据,而作的转换,而不是 ArrayBuffer 真的拥有这些数据,毕竟对象名称看起来也不是那么正式(用[[]]
包含)用
arrayBuffer[0] = 1
给 ArrayBuffer 对象的某个下标赋值是不会报错的,并且稍后你能够用一样的路径取出该值console.log(arrayBuffer[0]) // 1
, 但这并不表明你操做了 ArrayBuffer 的数据,道理跟给数组设置属性
相同.
let arrayBuffer = new ArrayBuffer(8); let dataView = new DataView(arrayBuffer); console.log(dataView.getUint8(1)); // 0 dataView.setUint8(1, 2); console.log(dataView.getUint8(1)); // 2 console.log(dataView.getUint16(1)); // 512 dataView.setUint16(1, 255); console.log(dataView.getUint16(1)); // 255 console.log(dataView.getUint8(1)); // 0
就像你看到的,咱们能够在同一个数据上面,调用不一样的方法,读取/写入 不一样类型(长度)的数据,可是大部分状况下,这么作会很可贵到咱们预期的效果.就像上面的输出,看起来好像不是那么的正常,这是由于 一个 16 位的二进制,用 8 位的格式来读,恰好能够读成 2 个 8 位的二进制.举个栗子
// 16 位的 1 0000 0000 0000 0001 // 用 8 位的读就变成 0000 0000 // 0 0000 0001 // 1
由于前面 8 位恰好都是 0 , 因此结果看起来除了多个 0 彷佛没啥区别? 当数字比较大的时候
// 应该是256? 我也不太会算这个 0000 0001 0000 0001 // 用 8 位的读就变成 0000 0001 // 1 0000 0001 // 1
扯远了,咱们回头看看 DataView 提供了哪些方法
// 读 DataView.prototype.getInt8() DataView.prototype.getUint8() DataView.prototype.getInt16() DataView.prototype.getUint16() DataView.prototype.getInt32() DataView.prototype.getUint32() DataView.prototype.getFloat32() DataView.prototype.getFloat64() // 写 DataView.prototype.setInt8() DataView.prototype.setUint8() DataView.prototype.setInt16() DataView.prototype.setUint16() DataView.prototype.setInt32() DataView.prototype.setUint32() DataView.prototype.setFloat32() DataView.prototype.setFloat64()
跟 TypedArray 比 少了一个 Uint8ClampedArray() 具体看 MDN: DataView
base64 这个利器,相信前端的你不会陌生吧,最经常使用的操做可能就是图片转 base64 了吧? 在以前 要在字符串跟 base64 直接互转,咱们可能须要去网上拷一个别人的方法,并且大部分状况下,你没有时间去验证这个方法是否是真的可靠,有没有 bug, 如今咱们能够直接用内置的方法了
let str = 'I am a string'; let a = btoa(str); // a = 'SSBhbSBhIHN0cmluZw==' let b = atob(a); // b = 'I am a string'
没错,就是这么简单,并且大部分浏览器都支持 除了 IE9-, 具体能够参考 CanIUse: atob
btoa 方法不支持中文和特殊字符,因此保险起见,在转换以前仍是 encodeURIComponent 一下吧, 固然别忘了在 atob 后,再 decodeURIComponent 回来。
最后再安利 3 个包
jspack https://github.com/pgriess/no... js操做二进制文件, 咱们的 psd 文件解析就用到这个包.
jszip https://github.com/Stuk/jszip js操做压缩文件, 咱们的 pptx 的压缩比解析成 xml 都靠它.
xml2js https://github.com/Leonidas-f... 把 xml 文件转换成 json, 咱们的 pptx 解析就是用它进行 pptx 的 xml 文件的转换.
咱们40人的前端团队常年招兵买马中,在厦门的和想来厦门的童鞋们,不要吝惜你的简历,使劲砸过来 邮箱:atob('bnVveWFAZ2FvZGluZy5jb20=')
, 期待你一块儿来稿
事