我正在尝试使用 JavaScript 中的
FileApi
访问文本文件的前几行。
为此,我从文件开头切取任意数量的字节,并将 blob 交给
FileReader
。
对于大文件,这需要很长时间,尽管我目前的理解是只需要访问文件的前几个字节。
我目前已经在 Chrome 和 Edge (chromium) 中进行了测试。
使用性能开发工具在 Chrome 中进行的分析显示,在
reader.onloadend
之前有大量空闲时间,并且 RAM 使用量没有增加。然而,这可能是因为 FileApi
是在浏览器本身中实现的,并且不会反映在 JavaScript 性能统计数据中。
我的 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');
});
只是为了好玩,这里有一个工作线程和文件系统访问 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()
);
编辑:
忘记了,但是你需要铬,抱歉(在边缘测试) 这也不会在 jsfiddle 中运行,因为网络工作者等等安全等等。不过,您可以将其复制粘贴到谷歌的控制台中。由于某种原因,标头不会阻止 Thins 运行。如果这确实有帮助,请实际将工作人员放入自己的文件中(并将我的艺术负空间三角形重新格式化为不存在)
我认为在你的情况下要获取文件浏览器的切片仍然必须读取整个文件以从原始文件创建切片
订阅
progress
事件可能有助于更快地访问文件内容,然后中止读取过程
reader.addEventListener("progress", (event) => {});
Blob 接口的 slice() 方法创建并返回一个新的 Blob 对象,其中包含调用它的 Blob 子集的数据。
我们可以从 Blob 类的 chrome 自述文件中得到相同的结论
这个怎么样!!
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);
});