前端代码:(执行文件切片循环上传并最后发起结束合并请求)
async ApiUploadBigFile(file){
let bytesPerPiece = 1*1024*1024;//切片大小
let start = 0;
let end;
let index = 0;
let file_size = file.size;
let file_name = file.name;
let totalPieces = Math.ceil(file_size / bytesPerPiece);
let timestamp = new Date().getTime();
while(start < file_size){
end = start + bytesPerPiece;
if(end > file_size){
end = file_size;
}
let chunk = file.slice(start, end);//执行切片操作
let sliceName = file_name + "." + index;
let formData = new FormData();
formData.append('timestamp', timestamp);
formData.append('name', sliceName);
formData.append('size', file_size);
formData.append('total', totalPieces);
formData.append('index', index);
formData.append('file', chunk);//将表单id、文件、文件名输入form表单中,如果第三个参数不设置,则默认使用blob作为文件名
let res1 = await axios.post(`${API_ROOT}file/uploadBigFile`, formData);
if(res1.data.code == 1){
console.log(`已传输${index+1}个切片,共${totalPieces}个切片`)
this.uploadPercentage = Math.ceil((index+1)/totalPieces*100);
start = end;
index++;
}else{
Promise.reject("文件传输过程中服务器发生错误");
return;
}
}
let formDataFinish = new FormData();
formDataFinish.append('timestamp', timestamp);
formDataFinish.append('name', file_name);
formDataFinish.append('size', file_size);
formDataFinish.append('total', totalPieces);
axios.post(`${API_ROOT}file/uploadBigFileFinish`, formDataFinish).then((res)=>{
if(res.data.code == 1){
Promise.resolve("合并成功");
this.$message.success("文件上传成功");
this.uploadPercentage = 0;
}else{
Promise.reject("文件合并过程中服务器发生错误");
}
});
},
后端接口(接受切片文件)
var router = require('koa-router')();
const { mkdirsSync } = require('../utils/dir');
fs=require('fs');
path=require('path');
// 文件上传
let uploadPath = path.resolve(__dirname, '../upload'); //'F:\\aitools_node\\upload'
router.post('/uploadBigFile', async (ctx, next) => {
// 根据文件hash创建文件夹,把默认上传的文件移动当前hash文件夹下。方便后续文件合并。
const { timestamp, name, size, total, index} = ctx.request.fields;
const chunksPath = path.join(uploadPath, `/file_temp${timestamp}/`); //F:\aitools_node\upload\/file_temp${timestamp}/
if(!fs.existsSync(chunksPath)){ //判断文件夹是否存在
mkdirsSync(chunksPath);
}
fs.renameSync(ctx.request.fields.file[0].path, chunksPath + timestamp + name); //改名字
ctx.body={
code: 1,
msg: '上传成功,可继续传输'
};
})
// 文件合并
router.post('/uploadBigFileFinish', async (ctx, next) => {
const { timestamp, name, size, total } = ctx.request.fields;
// 创建存储文件
// 合并
const chunksPath = path.join(uploadPath, `/file_temp${timestamp}/`); //F:\aitools_node\upload\
const filePath = path.join(uploadPath, timestamp + name); //生成的文件名
// 读取所有的chunks 文件名存放在数组中
const chunks = fs.readdirSync(chunksPath);//读取目录下的所有文件
// 创建存储文件
if(chunks.length != total || chunks.length == 0) {
ctx.body={
code: 1,
msg: '切片文件数量不符合'
};
chunks.forEach((item)=>{
fs.unlinkSync(chunksPath + item);
});
fs.rmdirSync(chunksPath);
return;
}else{
fs.writeFileSync(filePath, '');
for (let i = 0; i < total; i++) {
// 追加写入到文件中
fs.appendFileSync(filePath, fs.readFileSync(chunksPath + timestamp + name + '.' + i));
// 删除本次使用的chunk
fs.unlinkSync(chunksPath + timestamp + name + '.' + i);
}
fs.rmdirSync(chunksPath);
// 文件合并成功,可以把文件信息进行入库。
ctx.body={
code: 1,
msg: '切片文件合并成功',
data: {
url: timestamp + name
}
};
}
})
module.exports = router.routes();
const path = require('path');
const fs = require('fs-extra');
// mkdirsSync函数
const mkdirsSync = (dirname) => {
if(fs.existsSync(dirname)) {
return true;
} else {
if (mkdirsSync(path.dirname(dirname))) {
fs.mkdirSync(dirname);
return true;
}
}
}
module.exports = {
mkdirsSync
};
以上就是文件切片上传,支持多人同时操作。