Ionic 6 Capacitor写入ZIP内SQLite文件到Documents目录报错排查
问题根因
- 二进制文件读取逻辑错误:
.sqlite属于二进制格式文件,原有代码使用compressedFile.async('string')读取会直接破坏二进制字节结构,不仅会导致文件损坏,乱码字节还会触发写入校验失败。 - Capacitor Filesystem 插件使用方式错误:该插件并非不支持二进制文件写入,只是要求二进制内容转为Base64格式字符串传入,同时指定对应编码参数即可,无需额外引入Cordova生态的文件插件。
- 路径参数配置隐患:原有写入方法
recursive设为false,如果压缩包内存在多层子目录,会因为父目录未创建直接抛出写入失败错误。
可直接运行的修复方案
1. 新增ArrayBuffer转Base64工具方法
该方法兼容iOS与Electron环境,无额外依赖:
private arrayBufferToBase64(buffer: ArrayBuffer): string { const bytes = new Uint8Array(buffer); let binaryStr = ''; for (let i = 0; i < bytes.byteLength; i++) { binaryStr += String.fromCharCode(bytes[i]); } return window.btoa(binaryStr); }
2. 修改JSZip解压读取逻辑
二进制文件统一读取为ArrayBuffer格式,转Base64后再传入写入方法,禁止用string模式读取二进制文件:
public async unzipFolder(file: File): Promise<string[]> { const zip: JSZip = await JSZip.loadAsync(file); const promises: Promise<string>[] = []; zip.forEach((relativePath: string, zipFile: JSZipObject) => { // 跳过目录项,只处理文件 if (!zipFile.dir) { promises.push(this.unzipFile(zipFile)); } }); return await Promise.all(promises); } public async unzipFile(compressedFile: JSZipObject): Promise<string> { // 统一用arraybuffer模式读取,兼容文本、二进制所有类型文件 const fileBuffer = await compressedFile.async('arraybuffer'); const base64Data = this.arrayBufferToBase64(fileBuffer); return this.fileOpsService.write(compressedFile.name, base64Data); }
3. 修改Capacitor Filesystem写入逻辑
显式指定Base64编码,开启递归创建目录:
import { Filesystem, Directory, Encoding, WriteFileResult } from '@capacitor/filesystem'; public async write( path: string, data: string, directory: Directory = Directory.Documents ): Promise<WriteFileResult> { return await Filesystem.writeFile({ path: path, directory: directory, data: data, recursive: true, // 二进制文件写入必须指定Base64编码 encoding: Encoding.Base64 }); }
之前尝试方案无效的原因说明
- 读取为ArrayBuffer/Blob格式无效:是因为没有将二进制内容转为Base64字符串传入,Capacitor Filesystem插件不支持直接接收ArrayBuffer/Blob类型参数,仅接受字符串格式的内容。
- 修改编码为UTF-8/UTF-16/ASCII无效:这类编码仅适用于纯文本文件,二进制文件必须使用Base64编码传入才能保证字节信息不丢失。
- Cordova File插件报错:Capacitor环境对Cordova插件的文件沙箱路径做了隔离,直接调用会出现路径映射不匹配问题,且XCode中抛出的
QLThumbnailErrorDomain日志属于系统选择文件时的缩略图关联警告,和写入失败无直接关联,可直接忽略。
平台适配说明
- iOS端:Capacitor默认拥有Documents目录的读写权限,无需额外配置权限描述文件,写入的sqlite文件可直接被相关sqlite插件读取。
- Electron端:上述代码可直接运行,文件会默认存储到Electron应用对应的用户文档目录下,无需额外适配。
内容的提问来源于stack exchange,提问作者N0M4D
相关产品推荐
相关产品推荐

