Chrome,FileReader API,event.target.result ===“”

2023-12-21

我有一个网络应用程序,它通过以下方式对大文本文件(> 500mb)进行一些处理FileReader API's readAsText() method.
多年来它一直运行良好,但突然我得到了空洞的回复:event.target.result是一个空字符串。

369MB 可以工作,但 589MB 不行。

我在多台电脑上测试过;结果相同,但它在 Firefox 中确实有效。 Chrome 肯定在最近的更新中引入了这一点。

这个bug已经提交了吗?

有什么解决方法吗?


这是 v8 对字符串长度的限制。

这个bug已经提交了吗?

这是负责任的承诺:https://github.com/v8/v8/commit/ea56bf5513d0cbd2a35a9035c5c2996272b8b728 https://github.com/v8/v8/commit/ea56bf5513d0cbd2a35a9035c5c2996272b8b728

运行我感觉的平分线此变更日志 https://chromium.googlesource.com/chromium/src/+log/21ed43fb0e53464aa6d07e18db680ace0468ae2b..d84a32443b2734e65c6fe6cda3aae04bee607bad发现它被应用在 Chrome v79 上。

在此更改之前,64 位平台上的限制设置为 1024MB,新限制为 512MB,即一半。

这意味着不仅 FileReader 受到影响,任何试图生成如此大字符串的方法也会受到影响。

这是一个简单的例子:

const header = 24;
const bytes = new Uint8Array( (512 * 1024 * 1024) - header );
let txt = new TextDecoder().decode( bytes );
console.log( txt.length ); // 536870888
txt += "f"; // RangeError

有什么解决方法吗?

解决该问题的唯一方法是按块处理文本。

幸运的是,您正在处理 ASCII 数据,因此您可以轻松地分割资源并使用以下命令处理该块:Blob.slice() https://developer.mozilla.org/en-US/docs/Web/API/Blob/slice method:

// working in a Web-Worker to not freeze the tab while generating the data
const worker_script = `
(async () => {

  postMessage( 'Generating file, may take some time...' );

  const bytes = Uint8Array.from(
    { length: 800 * 1024 * 1024 },
    (_, i) => (i % 25) + 65
  );
  const blob = new Blob( [ bytes ] );

  const length = blob.size;
  const chunk_size = 128 * 1024 * 1024;

  postMessage( 'Original file size: ' + length );
  
  let As = 0;
  let i = 0;
  while ( i < length ) {
    const str = await blob.slice( i, i + chunk_size ).text();
    i += chunk_size;
    As += str.split( 'A' ).length - 1;
  }
  postMessage( 'found ' + As + ' "A"s in the whole file' );

} )();
`;
const worker_blob = new Blob( [ worker_script ] );
const worker = new Worker( URL.createObjectURL( worker_blob ) );
worker.onmessage = (evt) => console.log( evt.data );

使用 UTF-8 等富文本的人必须处理多字节字符,这可能并不那么容易......

另请注意,即使在允许您生成如此大字符串的浏览器中,您也可能会面临其他问题。例如,在 Safari 中,您可以生成更大的字符串,但如果您将其在内存中保留的时间太长,则浏览器将自动重新加载您的页面。


2021年更新

现在几乎所有现代浏览器都支持Blob.stream()返回 ReadableStream 的方法,使我们能够很好地...以流的形式读取该 Blob 的内容。因此,我们可以以更高效的方式处理巨大的文件文本,并且由于 TextDecoder API 的流选项,我们甚至可以处理非 ASCII 字符:

const bytes = Uint8Array.from(
  { length: 800 * 1024 * 1024 },
  (_, i) => (i % 25) + 65
);
const blob = new Blob( [ bytes ] );

console.log( 'Original file size: ' + blob.size );
const reader = blob.stream().getReader();
const decoder = new TextDecoder();
let As = 0;
reader.read().then( function process({ done, value }) {
  const str = decoder.decode( value, { stream: true } );
  As += str.split( 'A' ).length - 1;
  if( !done ) {
    reader.read().then( process );
  }
  else {
    console.log( 'found ' + As + ' "A"s in the whole file' );
  }
} );
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Chrome,FileReader API,event.target.result ===“” 的相关文章

随机推荐