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

如何存储包含大体积二进制数据及其他字段值的JS对象?

问题描述

当前需要存储同时包含普通类型值、二进制文件数据的JS对象,预期存储结构如下:

{
  "value":"xyz",
  "file1":"[FileContent]",
  "file2":"[LargeFileContent]"
}

此前无二进制数据时,一直使用JSON格式存储所有内容。引入二进制数据后,处理1GB以上大文件时出现异常。
之前尝试过将二进制数据序列化为base64编码后存入JSON的方案,该方案处理20MB左右小文件时运行正常,但处理大文件时FileReader返回结果为空字符串,最终得到的异常结构如下:

{
   "value":"xyz",
   "file1":"[FileContent]",
   "file2":""
}

当前读取Blob的实现代码如下:

const readFiles = async (measurements: FormData) => {
    setFiles([]); // 结果存储位置
    let promises: Array<Promise<string>> = [];
    measurements.forEach((value) => {
      let dataBlob = value as Blob;
      console.log(dataBlob); // 此处打印Blob对象正常
      promises.push(
        new Promise((resolve, reject) => {
          const reader = new FileReader();
          reader.readAsDataURL(dataBlob);
          reader.onloadend = function () {
            resolve(reader.result as string);
          };
          reader.onerror = function (error) {
            reject(error);
          };
        })
      );
    });
    let result = await Promise.all(promises);
    console.log(result); // 大文件对应项为空
    setFiles(result);
  };

原因说明

Base64编码本身存在33%的体积膨胀,再加上JS中字符串每个字符占2字节的存储开销,1GB原始文件转成base64后需要占用近2.7GB内存,很容易触发浏览器单标签页的内存限制,直接导致FileReader读取失败返回空值,这也是小文件正常、大文件异常的核心原因。

可行方案
  • 方案1:使用multipart/form-data格式替代纯JSON
    这是处理混合普通字段+二进制文件数据的标准方案,不需要做任何编码转换,不会产生额外体积开销,也不会触发大文件内存问题:
    • 普通文本字段直接按键值对存入FormData
    • 二进制文件字段直接以Blob/File对象存入,无需转码
    • 浏览器原生支持该格式的解析、传输,无额外依赖
      如果需要本地持久化存储,可以直接将FormData对象存入IndexedDB,不需要做序列化处理。
  • 方案2:分块读取转码,避免一次性加载全量文件到内存
    如果必须使用JSON类结构化存储,不要一次性读取整个大文件转base64:
    1. 将大文件按固定大小(推荐10MB/块)切分
    2. 逐块读取转base64,按顺序存入数组
    3. 存储结构中将大文件字段替换为分块后的base64数组
    4. 使用时再逐块拼接还原
      核心分块读取逻辑参考:
    const readLargeFileInChunks = async (file: Blob, chunkSize = 10 * 1024 * 1024) => {
      const chunks: string[] = [];
      let offset = 0;
      while(offset < file.size) {
        const chunk = file.slice(offset, offset + chunkSize);
        const base64Chunk = await new Promise<string>((resolve, reject) => {
          const reader = new FileReader();
          reader.readAsDataURL(chunk);
          reader.onload = () => resolve(reader.result as string);
          reader.onerror = reject;
        });
        chunks.push(base64Chunk);
        offset += chunkSize;
      }
      return chunks;
    }
    
    该方案可以将单步内存占用控制在块大小的膨胀范围内,不会触发内存溢出。
  • 方案3:普通数据与二进制数据分离存储
    不要把二进制数据塞进JSON结构:
    • 普通JSON结构只存储文本字段、以及二进制文件的元信息(文件名、大小、类型、存储索引)
    • 大文件二进制数据直接以Blob格式存入IndexedDB、或者Cache API缓存目录
    • 使用时先读取JSON拿到元信息,再根据存储索引取对应的二进制数据
      该方案是前端本地存储大体积混合数据的通用最佳实践,完全规避序列化、编码带来的性能和内存问题。

不建议继续尝试全量base64编码大文件的方案,除了内存溢出问题外,转码过程还会阻塞事件循环导致页面长时间卡顿,GB级文件场景下性能表现极差。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 13:51:24