# 文件切片上传 **Repository Path**: Luomenghao/file-chunk-upload ## Basic Information - **Project Name**: 文件切片上传 - **Description**: javascript文件切片上传 - **Primary Language**: JavaScript - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 1 - **Created**: 2022-07-16 - **Last Updated**: 2024-06-06 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## 文件切片上传 ### 1.Client #### 获取文件的MD5值 ```javascript /** * 获取文件MD5值 * @param {File} file * @param {Number} chunkSize 切片大小 * @return {Promise} */ const getFileMd5 = (file, chunkSize) => { return new Promise(resolve => { const blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice const md5 = new SparkMD5(); const fr = new FileReader(); let index = 0; const loadFile = () => { const slice = blobSlice.call(file, index, index + chunkSize); fr.readAsBinaryString(slice); } loadFile(); fr.onload = (e) => { md5.appendBinary(e.target.result); if (index < file.size) { index += chunkSize; loadFile() } else { resolve(md5.end()) } } }) } ``` ### 2.Server #### Stream文件切片合并成一个文件 ```javascript /** * 多个文件合并成一个文件 * @param {String} chunkDir 切片目录 * @param {String} dataDir 最后生成的文件目录 * @param {String} fileName 文件名称 * @param {Function} sortFn 排序方法,排序后返回新的列表 * @return {Promise} */ const mergeChunks = (chunkDir, dataDir, fileName, sortFn) => { // 检测目录是否存在 if (!fs.existsSync(chunkDir)) { return Promise.reject(new Error('The chunk directory does not exist')) } let chunks = fs.readdirSync(chunkDir); // 所有chunks if (!chunks.length) { return Promise.reject(new Error('Chunk cannot be an empty directory')) } chunks = typeof sortFn === 'function' ? sortFn(chunks) : chunks.sort((a, b) => a - b); // 排序 const dataPath = path.resolve(dataDir, fileName); const writeChunkStream = fs.createWriteStream(dataPath); // 创建一个可写流 return new Promise((resolve, reject) => { mergeCore(chunks) function mergeCore(scripts) { if (scripts.length === 0) { return resolve(true) } const curChunk = path.resolve(chunkDir, scripts.shift()) const curChunkReadStream = fs.createReadStream(curChunk); // 获取当前的可读流 curChunkReadStream.pipe(writeChunkStream, { end: false }); // readStream 传输结束 则 递归 进行下一个文件流的读写操作 curChunkReadStream.on("end", () => { fs.unlinkSync(curChunk) // 删除chunkFile mergeCore(scripts); }) // 监听错误事件,关闭可写流,防止内存泄漏 curChunkReadStream.on("error", error => { writeChunkStream.close() resolve(error) }) } }) } // 调用 const mergedRes = await mergeChunks(chunkDir, UPLOAD_PATH, name, function sort(chunks) { return chunks.sort((a, b) => a.split('-').pop() - b.split('-').pop()) }).catch(err => { console.log("文件合并失败:", err) }) ```