JavaScript FileReader Slice 性能

JavaScript FileReader Slice Performance

提问人:kacase 提问时间:2/17/2021 最后编辑:Mark Schultheisskacase 更新时间:10/27/2023 访问量:1654

问:

我正在尝试使用 JavaScript 访问文本文件的前几行。FileApi

为此,我从文件开头切片任意数量的字节,并将 blob 移交给 .FileReader

对于大文件,这需要很长时间,尽管我目前的理解是只需要访问文件的前几个字节。

  • 后台是否有一些实现需要先访问整个文件,然后才能对其进行切片?
  • 它是否取决于 FileApi 的浏览器实现?

我目前已经在 Chrome 和 Edge (chromium) 中进行了测试。

使用性能开发工具在 Chrome 中的分析显示,在 Chrome 之前有大量空闲时间,并且 ram 使用率没有增加。但是,这可能是因为 是在浏览器本身中实现的,并且不会反映在 JavaScript 性能统计信息中。reader.onloadendFileApi

我的 FileReader 实现如下所示:

const reader = new FileReader();

reader.onloadend = (evt) => {
  if (evt.target.readyState == FileReader.DONE) {
    console.log(evt.target.result.toString());
  }
};

// Slice first 10240 bytes of the file
var blob = files.item(0).slice(0, 1024 * 10);

// Start reading the sliced blob
reader.readAsBinaryString(blob);

这工作正常,但如前所述,对于大文件的表现相当糟糕。我尝试了 10kb、100mb 和 6gb。记录前 10kb 的时间似乎与文件大小直接相关。

关于如何提高读取文件开头的性能的任何建议?


编辑: 遗憾的是,按照@BenjaminGruenbaum的建议使用 Response 和 DOM 流并不能提高读取性能。

var dest = newWritableStream({​​​​​​​​
    write(str) {​​​​​​​​
        console.log(str);
    }​​​​​​​​,
}​​​​​​​​);
var blob = files.item(0).slice(0, 1024 * 10);

(blob.stream ? blob.stream() : newResponse(blob).body)
// Decode the binary-encoded response to string
  .pipeThrough(newTextDecoderStream())
  .pipeTo(dest)
  .then(() => {​​​​​​​​
      console.log('done');
  }​​​​​​​​);

javascript blob filereader fileapi

评论

2赞 Benjamin Gruenbaum 2/17/2021
嘿,使用响应和 DOM 流有帮助吗?我不确定为什么这里很慢,因为在 blob 上使用应该只读取您想要的部分 - 但是您描述的内容表明它确实在等待整个文件。readAsBinarySring.slice
0赞 kacase 2/17/2021
@BenjaminGruenbaum使用 Response 和 DOM 流读取文件是有效的,但遗憾的是并没有提高大文件的读取性能。
0赞 kacase 2/17/2021
@BenjaminGruenbaum,我将 DOM Stream 实现添加到问题中。
4赞 Kaiido 2/24/2021
所以FileReader与它无关?为什么不在问题中说清楚呢?对我来说,这听起来就像您的操作系统花了这么多时间来触摸文件并生成元数据。恐怕没有什么 slice() 可以改变。至于为什么您的操作系统会花费相对于文件大小的时间,我不知道。可能值得在其他环境中进行测试,使用其他硬盘驱动器、其他文件系统等。
1赞 小聪聪到此一游 2/26/2021
并在加载文件期间读取文件的开头,而不是之后。

答:

-3赞 Anuj Shah 4/30/2022 #1

这个怎么样!!

function readFirstBytes(file, n) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => {
      resolve(reader.result);
    };
    reader.onerror = reject;
    reader.readAsArrayBuffer(file.slice(0, n));
  });
}

readFirstBytes('file', 10).then(buffer => {
  console.log(buffer);
});

评论

2赞 kacase 5/1/2022
这如何提高前 N 个字节的读取性能?您是否使用多种文件大小对其进行了测试?为什么这种方法与我帖子中描述的方法有什么不同?
0赞 Bobby Morelli 6/2/2023 #2

只是为了踢球,这里有一个工作线程和文件系统访问 API

不知道这些东西是否有帮助,我没有 6gb 文件。 这将使读数脱离主线程,因此在某种意义上确实有助于性能。

Object.assign(
    new Worker(
        URL.createObjectURL(
            new Blob(
                [
                    `self.onmessage = async (e) =>` +
                    `    void postMessage(` +
                    `        (new FileReaderSync())` +
                    `            .readAsText(` +
                    `                (await e.data.getFile())` +
                    `                    .slice(0,1024*10)` +
                    `            )` +
                    `    );`
                ],
                { type: 'application/javascript' }
            )
        )
    ),
    { onmessage: (e) => void console.log(e.data) }
).postMessage(
    (await window.showOpenFilePicker(
        { mode: 'read', startIn: 'documents' }
    )).pop()
);

编辑:

forgor,但你需要铬来做这个 rn 对不起(在 Edge 上测试) 此外,这不会在 jsfiddle 中运行,因为 Web Worker 等等,安全性等等。不过,您可以将其复制粘贴到Google上的控制台中。出于某种原因,标头不会阻止 Thins 运行。如果这确实有帮助,请把工人放在自己的文件中(并重新格式化我的艺术负空间三角形)

-2赞 Tomas 9/23/2023 #3

我认为在你的情况下,要获取文件浏览器的切片,仍然必须读取整个文件才能从原始文件创建切片

可能订阅该事件可以帮助更快地访问文件内容,然后中止读取过程progress

reader.addEventListener("progress", (event) => {});

根据 MDN 的说法

Blob 接口的 slice() 方法创建并返回一个新的 Blob 对象,该对象包含来自调用它的 blob 子集的数据。

我们可以从 chrome README for Blob 类中获得相同的结论

-1赞 libra 10/27/2023 #4

我在下面没有看到任何延迟运行代码。(dmg 文件大小为 ~220MB)

试试自己。

enter image description here