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

使用pinia-plugin-persistedstate持久化File数据遇问题求助

解决Pinia持久化File对象丢失的问题

问题根源

File是浏览器提供的特殊对象,包含文件内容、元数据等信息,但无法被JSON序列化。而pinia-plugin-persistedstate默认使用JSON来持久化Store状态,所以刷新页面后,原本存储的File对象无法被正确恢复,最终变成空Proxy。


解决方案

方案1:存储文件元数据+S3标识(推荐大文件使用)

不直接存储File对象,而是存储文件的元数据(文件名、类型、大小)和S3对象键,刷新页面后通过S3键重新请求文件。

修改后的Store代码:

export const useScanStore = defineStore('scans', {
    state: () => ({
      scanList: [] as PersistedScanInfo[],
    }),
    getters: {
      getScan: (state) => (id: string) => {
        return state.scanList.find(scan => scan.id === id);
      },
    },
    actions: {
      // 从S3重新获取文件并转为File对象
      async fetchScanFile(scan: PersistedScanInfo): Promise<File> {
        // 替换为你的S3下载接口逻辑
        const response = await fetch(`https://your-s3-bucket-url/${scan.s3Key}`);
        const blob = await response.blob();
        return new File([blob], scan.fileName, { type: scan.fileType });
      },
      // 添加扫描记录时存储元数据和S3键
      addScan(id: string, file: File, s3Key: string) {
        this.scanList.push({
          id,
          s3Key,
          fileName: file.name,
          fileType: file.type,
          fileSize: file.size,
        });
      },
    },
    persist: true,
  });

// 持久化存储的结构
interface PersistedScanInfo {
  id: string;
  s3Key: string; // S3对象唯一标识
  fileName: string;
  fileType: string;
  fileSize: number;
}

// 业务中使用的结构(包含File对象)
interface ScanInfo extends PersistedScanInfo {
  file?: File;
}

使用方式:刷新页面后,通过getScan获取到扫描记录,再调用fetchScanFile重新获取File对象。


方案2:将File转为Base64字符串存储(适合小文件)

把File对象转为Base64字符串(可被JSON序列化),持久化后再转回File对象。注意:Base64会比原文件体积大30%左右,且浏览器本地存储有大小限制(通常5-10MB),大文件不建议使用。

修改后的Store代码:

export const useScanStore = defineStore('scans', {
    state: () => ({
      scanList: [] as PersistedScanInfo[],
    }),
    getters: {
      getScan: (state) => (id: string) => {
        const persistedScan = state.scanList.find(scan => scan.id === id);
        if (!persistedScan) return null;

        // 将Base64转回File对象
        const byteString = atob(persistedScan.fileBase64.split(',')[1]);
        const arrayBuffer = new ArrayBuffer(byteString.length);
        const uint8Array = new Uint8Array(arrayBuffer);
        
        for (let i = 0; i < byteString.length; i++) {
          uint8Array[i] = byteString.charCodeAt(i);
        }

        return {
          id: persistedScan.id,
          file: new File([uint8Array], persistedScan.fileName, { type: persistedScan.fileType }),
        } as ScanInfo;
      },
    },
    actions: {
      // 添加扫描记录时将File转为Base64存储
      async addScan(id: string, file: File) {
        const fileBase64 = await new Promise<string>((resolve, reject) => {
          const reader = new FileReader();
          reader.onload = () => resolve(reader.result as string);
          reader.onerror = reject;
          reader.readAsDataURL(file);
        });

        this.scanList.push({
          id,
          fileBase64,
          fileName: file.name,
          fileType: file.type,
        });
      },
    },
    persist: true,
  });

// 持久化存储的结构
interface PersistedScanInfo {
  id: string;
  fileBase64: string;
  fileName: string;
  fileType: string;
}

// 业务中使用的结构
interface ScanInfo {
  id: string;
  file: File;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 13:47:02