You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Chrome中ReadableStreamBYOBReader.read忽略偏移量问题

Chrome中ReadableStreamBYOBReader忽略偏移量写入缓冲区的问题

问题概述

使用ReadableStreamBYOBReader实现零拷贝文件读取时,Chrome浏览器存在异常行为:调用read()方法传入带偏移量的Uint8Array视图时,阅读器未按指定偏移写入数据,而是覆盖了缓冲区开头的内容。该问题在MDN官方示例中同样可复现。

复现代码

<input type="file" onchange="upload(event)" />
<script>
    async function upload(event) {
        const reader = event.target.files[0].stream().getReader({ mode: 'byob' });

        let buffer = new ArrayBuffer(16777216);
        let offset = 0;

        const read1 = await reader.read(new Uint8Array(buffer, offset, 8388608));

        console.log('1', read1.value, new Uint8Array(read1.value.buffer));

        buffer = read1.value.buffer;
        offset += read1.value.byteLength;

        const read2 = await reader.read(new Uint8Array(buffer, offset, 8388608));

        console.log('2', read2.value, new Uint8Array(read2.value.buffer));
    }
</script>

预期行为

  • 每次read()返回的readX.value应为初始16MB缓冲区的偏移视图
  • 第一次读取后,缓冲区仅包含第一次读取的数据
  • 第二次读取后,第二次的数据应写入缓冲区的指定偏移位置,缓冲区包含两次读取的完整数据

浏览器表现对比

Firefox(符合预期)

1  Uint8Array(65536)  [   0,  0,  0, 32, 102, … ]  Uint8Array(16777216) [   0,  0,  0, 32, 102, … ]
2  Uint8Array(65536)  [ 100, 63, 56, 65, 149, … ]  Uint8Array(16777216) [   0,  0,  0, 32, 102, … ]

Chrome(异常行为)

1  Uint8Array(65536) [  0,   0,  0,  32, 102, …]  Uint8Array(16777216) [   0,  0,  0, 32, 102, …]
2  Uint8Array(524288) [ 28, 196, 91, 173, 156, …]  Uint8Array(16777216) [ 100, 63, 56, 65, 149, …]

问题细节

测试文件关键内容的位置:

  • [ 0, 0, 0, 32, 102]:文件起始位置
  • [100, 63, 56, 65, 149]:文件偏移65536字节处
  • [ 28, 192, 91, 173, 156]:文件偏移131072字节处

Chrome第二次读取时的异常:

  • 返回的read2.value包含了文件偏移131072字节处的内容
  • 本该写入缓冲区偏移65536字节处的文件数据([100, 63, 56, 65, 149])被错误写入缓冲区开头,完全忽略了传入的偏移量参数

注意:Chrome的读取块大小不固定(有时会读取几MB数据),仅当使用较大的缓冲区(如8MB)时才会触发该问题,小缓冲区场景下无法复现。

临时规避方案

目前可通过手动复制数据到目标偏移位置的方式绕过该问题,但会失去零拷贝的性能优势:

async function upload(event) {
    const reader = event.target.files[0].stream().getReader({ mode: 'byob' });

    let buffer = new ArrayBuffer(16777216);
    let offset = 0;

    // 第一次读取并手动复制
    let readResult = await reader.read(new Uint8Array(8388608));
    new Uint8Array(buffer, offset).set(readResult.value);
    offset += readResult.value.byteLength;

    // 第二次读取并手动复制
    readResult = await reader.read(new Uint8Array(8388608));
    new Uint8Array(buffer, offset).set(readResult.value);
    offset += readResult.value.byteLength;

    console.log('最终完整缓冲区', new Uint8Array(buffer));
}

内容的提问来源于stack exchange,提问作者Sinder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 04:11:09