File和Blob
在前端开发中,经常需要和文件
打交道,比如上传文件,下载文件等,在与文件打交道的同时,Blob也会经常出现,那么这个Blob是啥玩意儿?
什么是Blob
Blob这个名字来源最早出现在SQL数据库
中,表示Binary Large Object
,在JavaScript中,常常表示二进制
数据,它是一个指向数据块的引用
,先来看看它长啥样:
const aFileParts = ['<div id="app"><b>hey!</b></div>'] // 一个包含DOMString的数组
const oMyBlob = new Blob(aFileParts, { type: 'text/html' })
console.log(oMyBlob)
上面代码通过new Blob()
构造函数,构建了一个简单的blob对象,打印出来如下:
Blob只有两个属性,一个size
,表示文件的大小,一个type
,表示文件类型,看上去挺“寒酸”的。
什么是文件
既然Blob是一个类文件对象,那么真正的文件(File)是啥样呢?
<input type='file' id="myInput" />
我们可以通过本地上传文件获得真正的文件对象:
const inputDOM = document.getElementById('myInput')
inputDOM.onchange = event => {
const files = event.target.files
file = files[0]
}
上面的file变量,打印出来如下:
它也有两个属性,size
和type
,除此之外,还有一些其他属性,比如name
,lastModified
等。最重要的是,其原型对象的原型对象为Blob
,原来如此,File继承
自Blob。
说完了File和Blob本身,接下来,我们再来看看它们具体的应用场景。
文件下载:URL.createObjectURL()
文件下载
,当后端通过接口将下载的数据返回到前端后,前端需要做一些定制化的操作,通常将拿到的Blob对应到一个URL上,再进行下载。blob:http://0.0.0.0:5500/aa7a0993-2116-4ef9-9832-0f06ebc477e0
通过URL.createObjectURL()
获得的URL类似上面的样子,然后创建一个a
标签,将其值赋值给href
属性:
fetch('http://localhost:3000')
.then(res => res.blob())
.then(blob => download(blob))
function download(file) {
const fileUrl = URL.createObjectURL(file)
const aTag = document.createElement('a')
aTag.href = fileUrl
const fileName = 'demo.jpg'
aTag.download = fileName
document.body.appendChild(aTag)
aTag.click()
aTag.remove()
URL.revokeObjectURL(fileUrl)
}
注意:最后记得调用URL.revokeObjectURL()
来释放这些 URL 对应数据的占用内存。
服务端代码如下:
const http = require('http')
const path = require('path')
const fs = require('fs')
const mimeType = 'image/jpeg' // 'application/pdf'
const fileName = 'AI.jpg'
const server = http.createServer((req, res) => {
res.setHeader('Access-Control-Allow-Origin', '*')
res.setHeader('Content-Type', mimeType)
const filePath = path.join(__dirname, fileName)
const stream = fs.createReadStream(filePath)
stream.on('data', function (chunk) {
res.write(chunk)
})
stream.on('end', function () {
res.end()
})
})
server.listen(3000)
读取Blob:FileReader
通过上面的例子可以看出,Blob其实是一个“不透明
”的大数据块,通过Blob URL只能间接的访问其内容,如果要直接操作其中的数据,有什么办法吗?可以通过FileReader
对象,它能够异步
读取Blob中的内容。
其中,最常用的一个场景是,读取图片内容,并在页面上显示预览,来看一个例子:
<img src="" height="200" alt="Image preview...">
读取函数如下:
function readBlob(blob) {
const preview = document.querySelector('img');
const reader = new FileReader()
reader.addEventListener("load", function () {
preview.src = reader.result;
}, false)
if (blob) {
reader.readAsDataURL(blob)
}
}
图片会被读取为base64格式,类似:data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAkACQAAD/4QpZ...
这种格式,当读取完成后,触发load
事件,获得的结果会存入result
属性中。
参考
- Blob()-MDN
- David Flanagan. JavaScript:The Definitive Guide, 6th