Ionic 3多类型文件批量上传及大文件Base64转换报错求助
解决方案:Ionic 3批量多类型文件上传及大文件问题处理
嗨,我帮你梳理下解决思路,你的问题主要分两部分:实现批量文件选择和解决大文件Base64转换失败,咱们一步步来:
一、先把单次选择改成批量文件选择
你现在的代码是单次选文件,要实现批量,推荐用cordova-plugin-document-picker插件,它支持Android和iOS批量选择多种格式的文件(jpg、png、doc、pdf这些都没问题)。
1. 安装插件(适配Ionic 3版本)
# 安装Cordova核心插件 ionic cordova plugin add cordova-plugin-document-picker # 安装Ionic Native包装器(Ionic 3需指定4.x版本) npm install @ionic-native/document-picker@4.20.0
然后在app.module.ts中导入并注册:
import { DocumentPicker } from '@ionic-native/document-picker'; @NgModule({ ... providers: [ ... DocumentPicker ] }) export class AppModule {}
2. 替换为批量选择文件的方法
把你原来的addImageORFileToEntry()改成支持批量的版本:
import { DocumentPicker } from '@ionic-native/document-picker'; import { File } from '@ionic-native/file'; import { Platform } from 'ionic-angular'; constructor( private plt: Platform, private documentPicker: DocumentPicker, private file: File ) {} // 批量选择文件 selectMultipleFiles() { this.documentPicker.pickMultiple({ type: '*/*' // 允许所有类型,也可指定格式如'image/*,application/pdf,application/msword' }).then((uris: string[]) => { console.log('选中的文件URIs:', uris); // 遍历处理每个选中的文件 uris.forEach(uri => { this.processFile(uri); }); }).catch(err => { console.error('选择文件失败:', err); }); }
二、解决大文件上传问题:放弃Base64,改用FormData直接上传
你遇到的大文件Base64转换失败,本质是Base64会把文件体积放大30%,且大文件转Base64会占用大量内存,容易导致崩溃或转换失败。最优方案是用FormData直接上传原生文件流,既高效又稳定。
1. 处理文件并构建FormData
完善processFile方法,把文件转成Blob并加入待上传列表:
// 存储待上传的文件Blob及文件名 private fileList: {blob: Blob, name: string}[] = []; processFile(uri: string) { if (this.plt.is('android')) { // Android下解析文件路径 this.file.resolveLocalFilesystemUrl(uri).then(fileEntry => { fileEntry.file(file => { const reader = new FileReader(); reader.onloadend = () => { const blob = new Blob([reader.result], { type: file.type }); this.fileList.push({blob, name: file.name}); console.log('已添加文件:', file.name); }; reader.readAsArrayBuffer(file); }); }).catch(err => console.error('Android文件处理失败:', err)); } else if (this.plt.is('ios')) { // iOS下解析文件路径 const pathParts = uri.split('/'); const fileName = pathParts.pop(); const filePath = pathParts.join('/'); this.file.readAsArrayBuffer(filePath, fileName).then(arrayBuffer => { // 根据文件名推断MIME类型 let mimeType = ''; if (fileName.endsWith('.jpg') || fileName.endsWith('.jpeg')) { mimeType = 'image/jpeg'; } else if (fileName.endsWith('.png')) { mimeType = 'image/png'; } else if (fileName.endsWith('.pdf')) { mimeType = 'application/pdf'; } else if (fileName.endsWith('.doc')) { mimeType = 'application/msword'; } const blob = new Blob([arrayBuffer], { type: mimeType }); this.fileList.push({blob, name: fileName}); console.log('已添加文件:', fileName); }).catch(err => console.error('iOS文件处理失败:', err)); } }
2. 批量上传到服务器
写一个上传方法,把所有文件加入FormData后发送POST请求:
import { HttpClient, HttpEventType } from '@angular/common/http'; constructor(private http: HttpClient) {} uploadFiles() { if (this.fileList.length === 0) { console.log('请先选择文件'); return; } const formData = new FormData(); // 把每个文件加入FormData,字段名可根据后端接口调整 this.fileList.forEach(item => { formData.append('files[]', item.blob, item.name); }); // 发送POST请求到你的服务器接口 this.http.post('https://your-server-url/upload', formData, { reportProgress: true, // 开启上传进度监听 observe: 'events' }).subscribe(event => { if (event.type === HttpEventType.UploadProgress) { const progress = Math.round((event.loaded / event.total) * 100); console.log(`上传进度: ${progress}%`); } else if (event.type === HttpEventType.Response) { console.log('上传成功:', event.body); // 上传完成后清空文件列表 this.fileList = []; } }, err => { console.error('上传失败:', err); }); }
三、如果必须用Base64上传(不推荐大文件)
如果因为后端限制必须用Base64,针对大文件可以尝试分块转换,但还是建议优先用FormData。这里给个优化后的Base64转换示例:
// 大文件分块转Base64(需配合后端分块接收逻辑) async convertLargeFileToBase64(fileEntry: FileEntry): Promise<string[]> { return new Promise((resolve, reject) => { fileEntry.file(file => { const chunkSize = 1024 * 1024; // 按1MB分块 const fileReader = new FileReader(); let offset = 0; const base64Chunks: string[] = []; fileReader.onload = (e) => { const chunkBase64 = btoa(String.fromCharCode(...new Uint8Array(e.target.result))); base64Chunks.push(chunkBase64); offset += chunkSize; if (offset >= file.size) { resolve(base64Chunks); } else { readNextChunk(); } }; fileReader.onerror = reject; const readNextChunk = () => { const blob = file.slice(offset, offset + chunkSize); fileReader.readAsArrayBuffer(blob); }; readNextChunk(); }); }); }
总结
- 用
cordova-plugin-document-picker实现批量文件选择,比你原来的单次选择插件更适配需求; - 大文件上传优先用FormData,从根源避免Base64的内存和体积问题;
- 代码已经兼容Android和iOS的文件路径处理,你可以根据后端接口调整FormData的字段名。
内容的提问来源于stack exchange,提问作者Binita Doriwala
相关产品推荐
相关产品推荐

