Skip to content

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 对比

ReaderAPI 风格内存占用性能浏览器兼容推荐场景
FileReader事件回调一般✅ 所有小文件、图片预览
ReadableStreamDefaultReaderasync/await现代浏览器✅ 日常开发首选
ReadableStreamBYOBReaderasync/await最低最好现代浏览器大文件、高性能需求
WritableStreamDefaultWriterasync/await现代浏览器文件保存、上传

基于 MIT 许可发布