|
| 1 | + |
| 2 | + |
| 3 | + |
| 4 | +> 本文首发在我的【[个人博客](http://www.pingan8787.com)】 |
| 5 | +> 更多丰富的前端学习资料,可以查看我的 **Github**: [《Leo-JavaScript》](https://github.com/pingan8787/Leo-JavaScript),内容涵盖**数据结构与算法**、**HTTP**、**Hybrid**、**面试题**、**React**、**Angular**、**TypeScript**和**Webpack**等等。 |
| 6 | +> 点个 Star 不迷路~ |
| 7 | +
|
| 8 | +欢迎阅读《前端知乎系列》: |
| 9 | + |
| 10 | +* [《【前端知乎】443- ArrayBuffer 与 Blob 对象详解》](https://juejin.im/post/5df838e3e51d455830351a3c) |
| 11 | + |
| 12 | + |
| 13 | + |
| 14 | + |
| 15 | +`File` 对象、`FileList` 对象与 `FileReader` 对象大家或许不太陌生,常见于文件上传下载操作处理(如处理图片上传预览,读取文件内容,监控文件上传进度等问题)。 |
| 16 | + |
| 17 | +那么本文将与大家深入介绍两者。 |
| 18 | + |
| 19 | +## 一、File 对象 |
| 20 | + |
| 21 | +### 1. 概念介绍 |
| 22 | + |
| 23 | +`File` 对象提供有关文件的信息,并允许网页中的 JavaScript 读写文件。 |
| 24 | + |
| 25 | +最常见的使用场合是表单的文件上传控件,用户在一个 `<input type="file">` 元素上选择文件后,浏览器会生成一个数组,里面是每一个用户选中的文件,它们都是 `File` 实例对象。 |
| 26 | + |
| 27 | +另外值得提到一点:`File` 对象是一种特殊 `Blob` 对象,并且可以用在任意的 `Blob` 对象的 `context` 中。比如说, `FileReader`, `URL.createObjectURL()`, `createImageBitmap()`, 及 `XMLHttpRequest.send()` 都能处理 `Blob` 和 `File`。 |
| 28 | + |
| 29 | + |
| 30 | +```js |
| 31 | +// HTML 代码如下 |
| 32 | +// <input id="fileItem" type="file"> |
| 33 | +const file = document.getElementById('fileItem').files[0]; |
| 34 | +file instanceof File // true |
| 35 | +``` |
| 36 | + |
| 37 | +### 2. 对象使用 |
| 38 | + |
| 39 | +浏览器原生提供一个 `File()` 构造函数,用来生成 `File` 实例对象。 |
| 40 | + |
| 41 | +```js |
| 42 | +const myFile = new File(bits, name[, options]); |
| 43 | +``` |
| 44 | + |
| 45 | +参数: |
| 46 | + |
| 47 | +* `bits`: |
| 48 | + |
| 49 | +一个数组,表示文件的内容。成员可以是 `ArrayBuffer`,`ArrayBufferView`,`Blob`,或者 `DOMString `对象的 `Array`,或者任何这些对象的组合。 |
| 50 | + |
| 51 | +通过这个参数,也可以实现 `ArrayBuffer`,`ArrayBufferView`,`Blob` 转换为 `File` 对象。 |
| 52 | + |
| 53 | +* `name`: |
| 54 | + |
| 55 | +字符串,表示文件名或文件路径。 |
| 56 | + |
| 57 | +* `options`: |
| 58 | + |
| 59 | +配置对象,设置实例的属性。该参数可选。可选值有如下两种: |
| 60 | + |
| 61 | +`type`: `DOMString`,表示将要放到文件中的内容的 MIME 类型。默认值为 `""` 。 |
| 62 | +`lastModified`: 数值,表示文件最后修改时间的 Unix 时间戳(毫秒)。默认值为 `Date.now()`。 |
| 63 | + |
| 64 | +示例: |
| 65 | + |
| 66 | +```js |
| 67 | +const myFile = new File(['leo1', 'leo2'], 'leo.txt', {type: 'text/plain'}); |
| 68 | +``` |
| 69 | + |
| 70 | +根据已有的 blob 对象创建 File 对象: |
| 71 | + |
| 72 | +```js |
| 73 | +const myFile = new File([blob], 'leo.png', {type: 'image/png'}); |
| 74 | +``` |
| 75 | + |
| 76 | + |
| 77 | +### 3. 实例属性和方法 |
| 78 | + |
| 79 | +#### 3.1 实例属性 |
| 80 | + |
| 81 | +实例有以下几个属性: |
| 82 | + |
| 83 | +* `File.lastModified`:最后修改时间。只读 |
| 84 | + |
| 85 | +自 UNIX 时间起始值(1970年1月1日 00:00:00 UTC)以来的毫秒数 |
| 86 | + |
| 87 | +* `File.name`:文件名或文件路径。只读 |
| 88 | + |
| 89 | +出于安全考虑,返回值不包含文件路径 。 |
| 90 | + |
| 91 | +* `File.size`:文件大小(单位字节)。只读 |
| 92 | +* `File.type`:文件的 MIME 类型。只读 |
| 93 | + |
| 94 | +```js |
| 95 | +// HTML 代码如下 |
| 96 | +// <input id="fileItem" type="file"> |
| 97 | +const myFile = document.getElementById('fileItem') |
| 98 | +myFile.addEventListener('change', function(e){ |
| 99 | + const file = this.files[0]; |
| 100 | + console.log(file.name); |
| 101 | + console.log(file.size); |
| 102 | + console.log(file.lastModified); |
| 103 | + console.log(file.lastModifiedDate); |
| 104 | +}); |
| 105 | +``` |
| 106 | + |
| 107 | +#### 3.2 实例方法 |
| 108 | + |
| 109 | +`File` 对象没有定义任何方法,但是它从 Blob 接口继承了以下方法: |
| 110 | + |
| 111 | +* `Blob.slice([start[, end[, contentType]]])` |
| 112 | + |
| 113 | +返回一个新的 `Blob` 对象,它包含有源 `Blob` 对象中指定范围内的数据。 |
| 114 | + |
| 115 | + |
| 116 | +### 4. 兼容性 |
| 117 | + |
| 118 | + |
| 119 | + |
| 120 | +## 二、FileList 对象 |
| 121 | + |
| 122 | +### 1. 概念介绍 |
| 123 | + |
| 124 | +`FileList` 对象是一个类数组对象,每个成员都是一个 `File` 实例,主要出现在两种场合: |
| 125 | + |
| 126 | +* 通过 `<input type="file">` 控件的 `files` 属性,返回一个 `FileList` 实例。 |
| 127 | + |
| 128 | +另外,当 `input` 元素拥有 `multiple` 属性,则可以用它来选择多个文件。 |
| 129 | + |
| 130 | +* 通过拖放文件,查看 `DataTransfer.files` 属性,返回一个 `FileList` 实例。 |
| 131 | + |
| 132 | +```js |
| 133 | +// HTML 代码如下 |
| 134 | +// <input id="fileItem" type="file"> |
| 135 | +const files = document.getElementById('fileItem').files; |
| 136 | +files instanceof FileList // true |
| 137 | + |
| 138 | +const firstFile = files[0]; |
| 139 | +``` |
| 140 | + |
| 141 | +### 2. 对象使用 |
| 142 | + |
| 143 | +所有 `type` 属性为 `file` 的 `<input>` 元素都有一个 `files` 属性,**用来存储用户所选择的文件**. 例如: |
| 144 | + |
| 145 | + |
| 146 | +### 3. 实例属性和方法 |
| 147 | + |
| 148 | +#### 3.1 实例属性 |
| 149 | + |
| 150 | +实例只有一个属性: |
| 151 | + |
| 152 | +* `FileList.length`:返回列表中的文件数量。只读 |
| 153 | + |
| 154 | + |
| 155 | +#### 3.2 实例方法 |
| 156 | + |
| 157 | +实例只有一个方法: |
| 158 | + |
| 159 | +* `FileList.item()`:用来返回指定位置的实例,从 0 开始。 |
| 160 | + |
| 161 | +由于 `FileList` 实例是个类数组对象,可以直接用方括号运算符,即` myFileList[0]` 等同于 `myFileList.item(0)` ,所以一般用不到 `item() `方法。 |
| 162 | + |
| 163 | +### 4. 兼容性 |
| 164 | + |
| 165 | + |
| 166 | + |
| 167 | +### 5. 实例 |
| 168 | + |
| 169 | +选择多个文件,并获取每个文件信息: |
| 170 | + |
| 171 | +```js |
| 172 | +// HTML 代码如下 |
| 173 | +// <input id="myfiles" multiple type="file"> |
| 174 | +const myFile = document.querySelector("#myfiles"); |
| 175 | +myFile.addEventListener('change', function(e){ |
| 176 | + let files = this.files; |
| 177 | + let fileLength = files.length; |
| 178 | + let i = 0; |
| 179 | + while ( i < fileLength) { |
| 180 | + let file = files[i]; |
| 181 | + console.log(file.name); |
| 182 | + i++; |
| 183 | + } |
| 184 | +}); |
| 185 | +``` |
| 186 | + |
| 187 | +## 三、FileReader 对象 |
| 188 | + |
| 189 | +### 1. 概念介绍 |
| 190 | + |
| 191 | +`FileReader` 对象允许 Web 应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 `File` 或 `Blob` 对象指定要读取的文件或数据。 |
| 192 | + |
| 193 | +简单理解,就是用于读取 `File` 对象或 `Blob` 对象所包含的文件内容。 |
| 194 | + |
| 195 | +### 2. 对象使用 |
| 196 | + |
| 197 | +浏览器原生提供一个 `FileReader` 构造函数,用来生成 `FileReader` 实例。 |
| 198 | + |
| 199 | +```js |
| 200 | +const reader = new FileReader(); |
| 201 | +``` |
| 202 | + |
| 203 | +### 3. 实例属性和方法 |
| 204 | + |
| 205 | +`FileReader` 对象拥有的属性和方法较多。 |
| 206 | + |
| 207 | +#### 3.1 实例属性 |
| 208 | + |
| 209 | +* `FileReader.error` : 表示在读取文件时发生的错误。只读 |
| 210 | +* `FileReader.readyState` : 整数,表示读取文件时的当前状态。只读 |
| 211 | + |
| 212 | +共有三种状态: |
| 213 | +0 : EMPTY,表示尚未加载任何数据; |
| 214 | +1 : LOADING,表示数据正在加载; |
| 215 | +2 : DONE,表示加载完成; |
| 216 | + |
| 217 | +* `FileReader.result` 读取完成后的文件内容。只读 |
| 218 | + |
| 219 | +仅在读取操作完成后才有效,返回的数据格式**取决于使用哪个方法来启动读取操作**。 |
| 220 | + |
| 221 | +#### 3.2 事件处理 |
| 222 | + |
| 223 | +* `FileReader.onabort` : 处理`abort`事件。该事件在读取操作**被中断**时触发。 |
| 224 | +* `FileReader.onerror` : 处理`error`事件。该事件在读取操作**发生错误**时触发。 |
| 225 | +* `FileReader.onload` : 处理`load`事件。该事件在读取操作**完成**时触发。 |
| 226 | +* `FileReader.onloadstart` : 处理`loadstar`t事件。该事件在读取操作**开始**时触发。 |
| 227 | +* `FileReader.onloadend` : 处理`loadend`事件。该事件在读取操**作结束**时(要么成功,要么失败)触发。 |
| 228 | +* `FileReader.onprogress` : 处理`progress`事件。该事件在读取**Blob**时触发。 |
| 229 | + |
| 230 | +#### 3.3 实例方法 |
| 231 | + |
| 232 | +* `FileReader.abort()`:终止读取操作,`readyState` 属性将变成2。 |
| 233 | +* `FileReader.readAsArrayBuffer()`:以 `ArrayBuffer` 的格式读取文件,读取完成后 `result` 属性将返回一个 `ArrayBuffer` 实例。 |
| 234 | +* `FileReader.readAsBinaryString()`:读取完成后, `result` 属性将**返回原始的二进制字符串**。 |
| 235 | +* `FileReader.readAsDataURL()`:读取完成后, `result` 属性将返回一个 Data URL 格式(Base64 编码)的字符串,代表文件内容。 |
| 236 | + |
| 237 | +对于图片文件,这个字符串可以用于`<img>`元素的 `src` 属性。注意,这个字符串不能直接进行 Base64 解码,必须把前缀 `data:*/*;base64` ,从字符串里删除以后,再进行解码。 |
| 238 | + |
| 239 | +* `FileReader.readAsText()`:读取完成后, `result` 属性将返回文件内容的文本字符串。 |
| 240 | + |
| 241 | +该方法的第一个参数是代表文件的 Blob 实例,第二个参数是可选的,表示文本编码,默认为 `UTF-8`。 |
| 242 | + |
| 243 | +### 4. 兼容性 |
| 244 | + |
| 245 | + |
| 246 | + |
| 247 | +### 5. 实例 |
| 248 | + |
| 249 | +这里举一个图片预览的实例: |
| 250 | + |
| 251 | +```js |
| 252 | +/* HTML 代码如下 |
| 253 | + <input type="file" onchange="previewFile()"> |
| 254 | + <img src="" height="200"> |
| 255 | +*/ |
| 256 | + |
| 257 | +function previewFile() { |
| 258 | + let preview = document.querySelector('img'); |
| 259 | + let file = document.querySelector('input[type=file]').files[0]; |
| 260 | + let reader = new FileReader(); |
| 261 | + |
| 262 | + reader.addEventListener('load', function () { |
| 263 | + preview.src = reader.result; |
| 264 | + }, false); |
| 265 | + |
| 266 | + if (file) { |
| 267 | + reader.readAsDataURL(file); |
| 268 | + } |
| 269 | +} |
| 270 | +``` |
| 271 | + |
| 272 | +## 四、参考资料 |
| 273 | + |
| 274 | +1. [《File 对象,FileList 对象,FileReader 对象》](https://wangdoc.com/javascript/bom/file.html) |
| 275 | +2. [MDN](https://developer.mozilla.org/zh-CN/docs/Web/API) |
| 276 | + |
| 277 | + |
| 278 | +## 五、关于我 |
| 279 | + |
| 280 | +> 本文首发在 [pingan8787个人博客](http://www.pingan8787.com),如需转载请保留个人介绍。 |
| 281 | +
|
| 282 | +|Author|王平安| |
| 283 | +|---|---| |
| 284 | +|E-mail|pingan8787@qq.com| |
| 285 | +|博 客|www.pingan8787.com| |
| 286 | +|微 信|pingan8787| |
| 287 | +|每日文章推荐|https://github.com/pingan8787/Leo_Reading/issues| |
| 288 | +|ES小册|js.pingan8787.com| |
| 289 | + |
| 290 | + |
| 291 | + |
0 commit comments