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

如何用JavaScript解压Base64格式的Zip文件及问题排查

从Base64编码的Zip文件提取内容的问题

问题1:fflate库使用报错

我有一段对应Zip文件的Base64字符串,需要提取其中的文件。最初使用fflate库尝试,代码如下:

attachmentsFlat.forEach(async (attachment) => {
  attachment = await emailStore.getAttachment(props.mailbox, attachment.email_id, attachment.id)
  if(attachment.file_name.split('.').pop() ==  'zip') {
    const decompressed = fflate.decompressSync(attachment.content_bytes);
    console.log(decompressed)
  }
})

运行后出现错误:

fflate.js?v=2017d673:285 Uncaught (in promise) TypeError: dat.subarray is not a function
at inflt (fflate.js?v=2017d673:285:21)
at inflateSync (fflate.js?v=2017d673:1103:10)
at Module.decompressSync (fflate.js?v=2017d673:1421:160)
at EmailFilesAssignment.vue:150:37

问题2:JSZip异步获取文件失败

改用JSZip后,无法正确异步获取文件,代码如下:

attachmentsFlat.forEach(async (attachment) => {
  attachment = await emailStore.getAttachment(props.mailbox, attachment.email_id, attachment.id)
  if(attachment.file_name.split('.').pop() ==  'zip') {
    const zipFiles = await uncompressZipAttachment(attachment)
    console.log(zipFiles) // 控制台显示有8条条目但数组为空
    console.log(zipFiles[0]) // 始终返回undefined
  }
})

const dataURLtoFile = (base64String: string, contentType: string | undefined, filename: string) => {
  let mime = contentType
  let bstr = atob(base64String) 
  let n = bstr.length
  let u8arr = new Uint8Array(n)
  while(n--){
    u8arr[n] = bstr.charCodeAt(n);
  }
  return new File([u8arr], filename, {type:mime});
}

const uncompressZipAttachment = async (attachment : FileAttachment) : Promise<any> => {
  let files : File[] = []
  const decompressedZipFiles = await jsZip.loadAsync(dataURLtoFile(attachment.content_bytes, attachment.content_type, attachment.file_name))
  decompressedZipFiles.forEach(async (filename) => {
    let fileData = await decompressedZipFiles.files[filename].async("blob"); 
    files.push(new File([fileData], filename))
  })
  return files
}

解决方案

修复fflate的使用问题

fflate的decompressSync需要接收Uint8Array类型的二进制数据,而非直接传入Base64字符串。先将Base64转为Uint8Array再传入:

attachmentsFlat.forEach(async (attachment) => {
  attachment = await emailStore.getAttachment(props.mailbox, attachment.email_id, attachment.id)
  if(attachment.file_name.split('.').pop() === 'zip') {
    // Base64转Uint8Array
    const bstr = atob(attachment.content_bytes);
    const u8arr = new Uint8Array(bstr.length);
    for (let i = 0; i < bstr.length; i++) {
      u8arr[i] = bstr.charCodeAt(i);
    }
    // 传入二进制数组解压
    const decompressed = fflate.decompressSync(u8arr);
    console.log(decompressed);
  }
})

修复JSZip的异步问题

forEach无法等待内部异步操作完成,导致函数提前返回空数组。改用Promise.all等待所有文件处理完成:

const uncompressZipAttachment = async (attachment: FileAttachment): Promise<File[]> => {
  // 直接将Base64转Uint8Array,无需转File对象,JSZip支持直接加载二进制数据
  const bstr = atob(attachment.content_bytes);
  const u8arr = new Uint8Array(bstr.length);
  for (let i = 0; i < bstr.length; i++) {
    u8arr[i] = bstr.charCodeAt(i);
  }

  const zip = await JSZip.loadAsync(u8arr);
  
  // 收集所有文件的异步处理Promise,跳过目录
  const filePromises = Object.keys(zip.files).map(async (filename) => {
    if (!zip.files[filename].dir) {
      const blob = await zip.files[filename].async("blob");
      return new File([blob], filename);
    }
  });
  
  // 过滤目录对应的undefined结果,等待所有操作完成
  const files = (await Promise.all(filePromises)).filter(Boolean);
  return files;
}

修改后zipFiles会正确返回解压后的文件数组,zipFiles[0]也能获取到对应文件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 05:12:44