import assert from "assert"; import { OakUploadException } from '../../types/Exception'; // 辅助方法:将文件切片 export async function sliceFile(file, chunkSize, partCount) { if (process.env.OAK_PLATFORM === 'wechatMp') { // 微信小程序环境下,file 可能是临时文件路径字符串 if (typeof file === 'string') { return sliceFileForMp(file, chunkSize, partCount); } else { assert(false, '小程序环境下得到不为string的文件'); } } assert(file instanceof File, '分片上传仅支持 File 类型的文件'); const chunks = []; for (let i = 0; i < partCount; i++) { const start = i * chunkSize; const end = Math.min(start + chunkSize, file.size); chunks.push(file.slice(start, end)); } return chunks; } // 小程序环境下的文件分片 export async function sliceFileForMp(filePath, chunkSize, partCount) { const fs = wx.getFileSystemManager(); const tempDir = `${wx.env.USER_DATA_PATH}/oak_upload_temp`; assert(chunkSize <= 10 * 1024 * 1024, '小程序下,单个分片大小不能超过 10MB'); // 微信小程序限制单个文件不能超过10MB // 确保临时目录存在 try { fs.accessSync(tempDir); } catch (e) { fs.mkdirSync(tempDir, false); } const chunks = []; // 读取文件信息 const fileStat = fs.statSync(filePath); assert(!Array.isArray(fileStat), '无法获取文件信息'); const fileSize = fileStat.size; // 读取每个分片并写入临时文件 for (let i = 0; i < partCount; i++) { const start = i * chunkSize; const length = Math.min(chunkSize, fileSize - start); try { // 读取分片数据 const data = await new Promise((resolve, reject) => { fs.readFile({ filePath: filePath, encoding: 'binary', position: start, length: length, success: (res) => resolve(res.data), fail: reject }); }); // 写入临时文件 const tempFilePath = `${tempDir}/chunk_${Date.now()}_${i}.temp`; await new Promise((resolve, reject) => { fs.writeFile({ filePath: tempFilePath, encoding: 'binary', data: data, success: () => resolve(), fail: reject }); }); chunks.push(tempFilePath); } catch (err) { console.error('分片读取失败:', err); // 清理已创建的临时文件 await cleanTempFiles(chunks); throw new OakUploadException(`分片 ${i + 1} 读取失败: ${err}`); } } return chunks; } // 清理临时文件 export async function cleanTempFiles(tempFiles) { if (process.env.OAK_PLATFORM !== 'wechatMp') { return; } const fs = wx.getFileSystemManager(); for (const filePath of tempFiles) { try { fs.unlinkSync(filePath); } catch (err) { console.warn(`清理临时文件失败: ${filePath}`, err); } } }