# 浏览器文件上传原理
现代网站的前端上传文件的流程主要是利用 input
标签读取到文件,再利用 ajax
将文件的数据发送到后端服务器。
因为 web 程序的运行环境是在浏览器里,在这个流程中 web 应用无法像直接运行在操作系统里的程序那样直接操作用户计算机上的文件。以前的做法是利用 <input type="file">
把文件放到一个表单中提交。而以前提交表单通常需要刷新页面,现代 web 应用发送数据基本都是利用 ajax
异步提交、获取数据。所以以前利用表单提交数据的方法做法就不太合适了。
为了解决 js
在浏览器环境中运行无法操作用户计算机文件的痛点,浏览器增加了 File API 和 Blob API 以增强 js
访问文件的能力。
# File API
HTML5 在 DOM 的事件对象上添加了 files 数组,这个集合里保存了一组 File 对象,用来标明用户选中的文件。File 对象中的属性保存着选中文件的相关信息。通过 Event
对象的 target
对象里的 files
属性我们可以访问到 File 对象。
<input id="inputBox" type="file" /> |
const inputBox = document.getElemetById('inputBox'); | |
inputBox.onChange = function(event){ | |
const selectedFile = event.target.files[0]; | |
console.log(selectedFile); | |
} |
File 对象部分属性说明
属性 | 作用 |
---|---|
name | 文件名称 |
size | 以字节为单位计算的文件大小 |
type | 文件的 MIME 类型 |
lastModified | 文件最后修改时间的时间戳 |
lastModifiedDate | 文件最后修改的时间 |
# FileReader 类型
FileReader 通常用于读取文件,它是一种异步读取文件的 API。它类似于 XMLHttpRequest
,只不过它是从本地计算机上读取数据,而不是通过网络读取远程计算机上的数据。
FileReader
对象允许 Web 应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 File
或 Blob
对象指定要读取的文件或数据。
const reader = new FileReader(); | |
console.log(reader); |
FileReader 部分属性说明
属性 | 说明 |
---|---|
error | 返回读取文件时的错误信息。 |
readyState | 表示文件读取的状态。0:reader 已创建;1:读取中;2:读取方法被调用。 |
result | 返回读取的文件内容。 |
onload | 事件。当文件读取成功时,触发该事件。若 error 事件被触发,则该事件不会被触发。 |
onloadstart | 事件。开始读取文件时,触发该事件。 |
onprogress | 事件。文件读取时,每过 50ms 触发一次该事件。 |
onloadend | 事件。当文件读取完成时,触发该事件,无论文件读取成功与否。 |
onerror | 事件。当文件读取失败时,触发该事件。 |
onabort | 事件。取消文件读取时触发该事件。 |
FileReader 类型提供了几个读取文件数据的方法分别用于不同场景。
# readAsText()
readAsText
方法可以将 Blob 或者 File 对象转根据特殊的编码格式转化为内容 (字符串形式),这个方法是异步的,
readAsText
执行完以后会将 readyState
属性改为 2,表示文件读取完成。
函数签名
instance of FileReader.readAsText(blob[, encoding]); |
使用实例
const reader = new FileReader(); | |
reader.readAsText(BlobObj, 'utf-8'); | |
reader.onload = (res) => { | |
console.log('result', reader.result); | |
} |
# readAsDataURL()
readAsDataURL
方法可以将 Blob 或者 File 对象转化为 base64 编码的字符串,这个方法也是异步的。
readAsDataURL
执行完以后会将 readyState
属性改为 2,表示文件读取完成。
函数签名
instance of FileReader.readAsDataURL(blob); |
使用实例
const reader = new FileReader(); | |
reader.readAsDataURL(BlobObj); | |
reader.onload = (res) => { | |
console.log('result', reader.result); | |
} |
# readAsBinaryString ()(废除)
readAsBinaryString
方法可以将 Blob 或者 File 对象转化为原始文件的二进制格式。
readAsBinaryString
执行完以后会将 readyState
属性改为 2,表示文件读取完成。
函数签名
instance of FileReader.readAsBinaryString(blob); |
使用实例
const reader = new FileReader(); | |
reader.readAsBinaryString(BlobObj); | |
reader.onload = (res) => { | |
console.log('result', reader.result); | |
} |
# readAsArrayBuffer()
用于替代 readAsBinaryString
。
# abort()
该方法可以取消 FileReader 的读取操作,触发之后 readyState
为已完成(DONE),值为 2。
函数签名
instanceOfFileReader.abort(); |
使用实例
const reader = new FileReader(); | |
setTimeout(() => reader.abort(), 100); |
# Blob 类型
Blob
对象表示一个不可变、原始数据的类文件对象。它的数据可以按文本或二进制的格式进行读取,也可以转换成 ReadableStream
来用于数据操作。
Blob 表示的不一定是 JavaScript 原生格式的数据。 File
接口基于 Blob
,继承了 blob 的功能并将其扩展以支持用户系统上的文件。
# 实现一个简单的图片上传
- 实现多张图片上传并限制图片大小小于 2MB
<input id="inputBox" type="file" accept="image/*" multiple="true" /> |
const inputBox = document.getElementById("inputBox"); | |
function checkImgSize(file){ | |
const limitSize = 2 * 2 ** 20; | |
return file.size < limitSize; | |
} | |
inputBox.onchange = function(event){ | |
const selectedFiles = this.files; | |
const isPass = selectedFiles.every(checkImgSize); | |
if (!isPass) return alert("请确保每张图片的大小都小于2MB"); | |
// do something | |
} |