主题
Reader
Stream 和 Reader 的关系
js
// Stream 是数据的"管道"
const stream = file.stream() // ReadableStream
// Reader 是读取管道数据的"工具"
const reader = stream.getReader() // ReadableStreamDefaultReader
// 通过 reader 读取数据
const { done, value } = await reader.read()类比理解:
- Stream = 水管
- Reader = 水龙头
- 数据 = 水流
Reader 的四种类型
FileReader(文件读取器)
特点:
- ✅ 兼容性最好(支持所有浏览器)
- ❌ 基于事件回调(不支持 async/await)
- ❌ 一次性读取整个文件到内存
- ✅ 支持多种格式输出
API
js
const reader = new FileReader()
// 读取方法(4选1):
reader.readAsText(file) // → 文本
reader.readAsDataURL(file) // → Base64(常用于图片预览)
reader.readAsArrayBuffer(file) // → ArrayBuffer
reader.readAsBinaryString(file) // → 二进制字符串(已废弃)
// 事件监听:
reader.onload = (e) => {
console.log(e.target.result) // 读取结果
}
reader.onprogress = (e) => {
console.log(`进度: ${e.loaded}/${e.total}`)
}
reader.onerror = (e) => {
console.error('错误:', e)
}完整示例
js
// 读取文本文件
function readFileAsText(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader()
reader.onload = (e) => resolve(e.target.result)
reader.onerror = (e) => reject(e)
reader.readAsText(file)
})
}
// 使用
const file = document.querySelector('input').files[0]
const text = await readFileAsText(file)
console.log(text)ReadableStreamDefaultReader(默认流读取器)
特点:
- ✅ 现代 API(支持 async/await)
- ✅ 流式读取(内存占用低)
- ✅ 可暂停/恢复
- ❌ 不支持旧浏览器(IE)
API
js
const stream = file.stream() // 或 response.body
const reader = stream.getReader()
// 读取数据
const { done, value } = await reader.read()
// done: boolean - 是否读取完成
// value: Uint8Array - 数据块(二进制)
// 其他方法
await reader.cancel() // 取消读取
reader.releaseLock() // 释放锁完整示例
js
// 流式读取文本文件
async function readStreamAsText(file) {
const stream = file.stream()
const reader = stream.getReader()
const decoder = new TextDecoder()
let result = ''
while (true) {
const { done, value } = await reader.read()
if (done) break
// value 是 Uint8Array,需要解码
result += decoder.decode(value, { stream: true })
}
return result
}
// 使用
const file = document.querySelector('input').files[0]
const text = await readStreamAsText(file)
console.log(text)ReadableStreamBYOBReader(自带缓冲区读取器)
BYOB = Bring Your Own Buffer
特点:
- ✅ 高性能(零拷贝)
- ✅ 手动控制缓冲区大小
- ❌ 只支持字节流(ReadableByteStream)
- ❌ 使用复杂
API
js
// 获取 BYOB reader
const reader = stream.getReader({ mode: 'byob' })
// 提供缓冲区读取
const buffer = new ArrayBuffer(64 * 1024) // 64KB
const { done, value } = await reader.read(new Uint8Array(buffer))完整示例
js
async function readWithBYOB(url) {
const response = await fetch(url)
const reader = response.body.getReader({ mode: 'byob' })
const buffer = new ArrayBuffer(64 * 1024) // 64KB 缓冲区
while (true) {
const { done, value } = await reader.read(new Uint8Array(buffer))
if (done) break
console.log('读取了', value.byteLength, '字节')
// 处理数据...
}
}WritableStreamDefaultWriter(写入器)
特点:
- ✅ 现代 API(支持 async/await)
- ✅ 流式写入
- ✅ 常用于文件保存
API
js
const writableStream = new WritableStream({... });
const writer = writableStream.getWriter();
await writer.write('数据'); // 写入
await writer. close(); // 关闭
await writer.abort(); // 中止
writer.releaseLock(); // 释放锁完整示例
js
// 保存文件到本地
async function saveFile(data, filename) {
// 请求用户选择保存位置
const fileHandle = await window.showSaveFilePicker({
suggestedName: filename,
})
// 创建可写流
const writableStream = await fileHandle.createWritable()
const writer = writableStream.getWriter()
// 写入数据
await writer.write(data)
// 关闭流
await writer.close()
console.log('保存成功')
}
// 使用
await saveFile('Hello, World!', 'test.txt')Reader 对比
| Reader | API 风格 | 内存占用 | 性能 | 浏览器兼容 | 推荐场景 |
|---|---|---|---|---|---|
| FileReader | 事件回调 | 高 | 一般 | ✅ 所有 | 小文件、图片预览 |
| ReadableStreamDefaultReader | async/await | 低 | 好 | 现代浏览器 | ✅ 日常开发首选 |
| ReadableStreamBYOBReader | async/await | 最低 | 最好 | 现代浏览器 | 大文件、高性能需求 |
| WritableStreamDefaultWriter | async/await | 低 | 好 | 现代浏览器 | 文件保存、上传 |
