文件操作相关
发表于更新于
文件操作相关
1. Blob、File、Base64 概述
1.1 Blob 对象
Blob(Binary Large Object) 是浏览器提供的一个原生对象,用于表示不可变的、原始数据的类文件对象。
二进制数据本质:
在计算机中,所有数据最终都以二进制形式存储和传输:
- 文本文件:每个字符对应一个或多个字节的二进制编码
- 图片文件:像素数据以二进制格式存储
- 音频/视频:采样数据以二进制格式存储
- 程序文件:机器码以二进制格式存储
Blob 的作用:
Blob 对象是浏览器中表示原始二进制数据的标准方式,它:
- 封装二进制数据:将底层的字节序列包装成高级对象
- 提供统一接口:无论数据来源如何,都提供相同的操作方式
- 支持流式处理:可以分片读取和处理大文件
特点:
- 不可变性:一旦创建,内容无法修改
- 原始数据:直接存储二进制字节,不进行任何编码转换
- 类文件对象:具有类似文件的结构,但没有文件名等元信息
- 内存效率:直接操作二进制数据,避免不必要的编码转换
创建方式:
1 2 3 4 5 6 7 8
| const blob1 = new Blob(['Hello World'], { type: 'text/plain' })
const blob2 = new Blob([new Uint8Array([1, 2, 3])], { type: 'application/octet-stream' })
const blob3 = new Blob([blob1, blob2])
|
常用属性和方法:
1 2 3 4 5 6
| const blob = new Blob(['Hello'], { type: 'text/plain' }) console.log(blob.size) console.log(blob.type)
const slice = blob.slice(0, 3)
|
1.2 File 对象
File 对象 继承自 Blob 对象,专门用于表示文件信息,包含了文件的元数据。
与 Blob 的关系:
File 对象本质上是带有元信息的 Blob:
- 数据部分:继承自 Blob,存储文件的二进制内容
- 元信息部分:添加文件名、类型、修改时间等文件属性
- 完全兼容:File 对象可以直接当作 Blob 使用
二进制数据流:
1
| 用户选择文件 → 浏览器读取文件系统 → 创建 File 对象 → 包含二进制数据 + 元信息
|
特点:
- 继承自 Blob:拥有 Blob 的所有特性和方法
- 包含元信息:文件名、最后修改时间、文件类型等
- 用户选择:通常通过
<input type="file"> 获取
- 二进制存储:文件内容以原始二进制形式存储
获取方式:
1 2 3 4 5 6 7 8 9
| const fileInput = document.querySelector('input[type="file"]') const file = fileInput.files[0]
const dropZone = document.querySelector('.drop-zone') dropZone.addEventListener('drop', (e) => { const file = e.dataTransfer.files[0] })
|
常用属性:
1 2 3 4 5 6
| const file = fileInput.files[0] console.log(file.name) console.log(file.size) console.log(file.type) console.log(file.lastModified) console.log(file.webkitRelativePath)
|
1.3 Base64 编码
Base64 是一种用64个可打印字符来表示二进制数据的编码方法。
二进制到文本的转换:
Base64 的核心作用是将二进制数据转换为文本格式:
- 输入:任意二进制数据(字节序列)
- 输出:可打印的 ASCII 字符字符串
- 目的:在文本协议中安全传输二进制数据
编码原理:
1
| 二进制数据 → 每3个字节(24位) → 分成4组(每组6位) → 映射到64个字符 → Base64字符串
|
为什么需要 Base64:
- 文本协议兼容:HTTP、SMTP 等协议只能传输文本
- 数据完整性:避免二进制数据在传输过程中被误解释
- 跨平台兼容:不同系统对二进制数据的处理方式可能不同
- 存储安全:某些存储系统不支持二进制数据
特点:
- 文本格式:可以用文本方式传输二进制数据
- 大小增加:编码后大小约为原数据的 4/3 倍(每3字节变成4字符)
- URL 安全:某些字符在 URL 中需要转义
- 可逆性:可以完全还原为原始二进制数据
字符集:
1 2 3 4 5
| A-Z (26个字符) a-z (26个字符) 0-9 (10个字符) + / (2个字符) = (填充字符)
|
使用场景:
1 2 3 4 5 6 7 8 9 10
| const dataUrl = 'data:text/plain;base64,SGVsbG8gV29ybGQ='
const base64String = 'SGVsbG8gV29ybGQ='
const jsonData = { image: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...' }
|
1.4 三者关系与二进制数据流
数据流转图:
1 2 3
| 文件系统(二进制) → File对象(二进制+元信息) → Blob对象(纯二进制) → Base64(文本编码) ↑ ↓ ↓ ↓ 原始数据 用户操作接口 内存操作接口 传输/存储接口
|
二进制数据关联:
- 共同基础:三者都基于相同的二进制数据
- 不同表示:同一份数据的不同表现形式
- 转换无损:转换过程中二进制内容保持不变
- 用途不同:针对不同的使用场景优化
关系说明:
- File 是 Blob 的子类:File = Blob + 文件元信息
- Blob ↔ Base64:二进制数据 ↔ 文本编码
- File ↔ Base64:通过 Blob 作为中间桥梁
- 数据一致性:转换过程中二进制内容完全一致
2. 文件上传
2.1 基本文件上传
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| export function upFile(data) { return request({ url: '/ruo/file/upload', method: 'post', data }) }
const uploadFile = (file) => { const formData = new FormData() formData.append('file', file) upFile(formData).then((res) => { form.fileId = res.fileId saveUp(form).then(() => { this.$refs.pdmEdit.hide() this.$message.success('修改成功!') }) }) }
|
2.2 文件上传进度监控
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| const uploadWithProgress = (file, onProgress) => { const formData = new FormData() formData.append('file', file) return request({ url: '/upload', method: 'post', data: formData, onUploadProgress: (progressEvent) => { const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total) onProgress(percentCompleted) } }) }
|
3. 文件下载
3.1 Blob 方式下载
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| export function downloadPdm(data) { return request({ url: '/ruo/file/downloadFile', method: 'get', params: data, responseType: 'blob' }) }
downloadPdm({ id: data.id }).then(res => { const fileName = decodeURIComponent(res.headers['content-disposition'].split('=')[1]) const link = document.createElement('a') link.download = fileName link.href = URL.createObjectURL(new Blob([res.data])) document.body.appendChild(link) link.click() URL.revokeObjectURL(link.href) document.body.removeChild(link) })
downloadPdm({ id: data.id }).then(res => { const fileName = decodeURIComponent(res.headers['content-disposition'].split('=')[1]) const link = document.createElement('a') link.href = window.URL.createObjectURL(new Blob([res.data])) link.target = '_blank' link.setAttribute('download', fileName + '.apk') link.click() document.body.removeChild(link) })
|
3.2 通用文件下载函数
1 2 3 4 5 6 7 8 9 10
| const downloadFile = (blob, fileName) => { const url = window.URL.createObjectURL(blob) const link = document.createElement('a') link.href = url link.download = fileName document.body.appendChild(link) link.click() document.body.removeChild(link) window.URL.revokeObjectURL(url) }
|
4. File、Blob、Base64 相互转换
4.1 File 转 Base64
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| const fileToBase64 = (file) => { return new Promise((resolve, reject) => { const reader = new FileReader() reader.onload = () => resolve(reader.result) reader.onerror = reject reader.readAsDataURL(file) }) }
const fileInput = document.querySelector('input[type=file]') const file = fileInput.files[0] fileToBase64(file).then(base64 => { console.log(base64) })
|
4.2 Base64 转 Blob
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| const base64ToBlob = (base64String, mimeType = '') => { const base64Content = base64String.split(',')[1] const byteCharacters = atob(base64Content) const byteNumbers = new Array(byteCharacters.length)
for (let i = 0; i < byteCharacters.length; i++) { byteNumbers[i] = byteCharacters.charCodeAt(i) }
const byteArray = new Uint8Array(byteNumbers) return new Blob([byteArray], { type: mimeType }) }
const base64String = 'data:text/plain;base64,SGVsbG8sIHdvcmxkIQ==' const blob = base64ToBlob(base64String, 'text/plain')
|
4.3 Blob 转 Base64
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| const blobToBase64 = (blob) => { return new Promise((resolve, reject) => { const reader = new FileReader() reader.onload = () => resolve(reader.result) reader.onerror = reject reader.readAsDataURL(blob) }) }
const blob = new Blob(['Hello, world!'], { type: 'text/plain' }) blobToBase64(blob).then(base64 => { console.log(base64) })
|
4.4 Base64 转 File
1 2 3 4 5 6 7 8
| const base64ToFile = (base64String, fileName, mimeType = '') => { const blob = base64ToBlob(base64String, mimeType) return new File([blob], fileName, { type: mimeType }) }
const base64String = 'data:text/plain;base64,SGVsbG8sIHdvcmxkIQ==' const file = base64ToFile(base64String, 'example.txt', 'text/plain')
|
4.5 File 转 Blob
1 2 3 4 5 6
| const file = document.querySelector('input[type=file]').files[0] const blob = file
const newBlob = new Blob([file], { type: file.type })
|
5. 实际应用场景
5.1 图片预览
1 2 3 4 5 6 7 8 9
| const previewImage = (file) => { const reader = new FileReader() reader.onload = (e) => { const img = document.createElement('img') img.src = e.target.result document.body.appendChild(img) } reader.readAsDataURL(file) }
|
5.2 文件压缩
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| const compressImage = (file, quality = 0.8) => { return new Promise((resolve) => { const canvas = document.createElement('canvas') const ctx = canvas.getContext('2d') const img = new Image() img.onload = () => { canvas.width = img.width canvas.height = img.height ctx.drawImage(img, 0, 0) canvas.toBlob(resolve, 'image/jpeg', quality) } img.src = URL.createObjectURL(file) }) }
|
5.3 大文件分片上传
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| const uploadLargeFile = async (file, chunkSize = 2 * 1024 * 1024) => { const chunks = [] let start = 0 while (start < file.size) { const end = Math.min(start + chunkSize, file.size) const chunk = file.slice(start, end) chunks.push(chunk) start = end } for (let i = 0; i < chunks.length; i++) { const formData = new FormData() formData.append('chunk', chunks[i]) formData.append('index', i) formData.append('total', chunks.length) formData.append('filename', file.name) await uploadChunk(formData) } }
|
6. 注意事项
- 内存管理:使用
URL.createObjectURL() 后记得调用 URL.revokeObjectURL() 释放内存
- 文件大小限制:Base64 编码会增加约33%的文件大小
- 浏览器兼容性:某些老版本浏览器可能不支持某些 API
- 安全性:上传文件时要注意文件类型验证和大小限制
7. 总结
File、Blob、Base64 是前端文件操作的核心概念:
- File:包含文件信息的对象,继承自 Blob
- Blob:二进制数据的容器,用于文件下载和传输
- Base64:文本格式的二进制数据表示,便于传输和存储