原生JS+KOA大型文件(G级)切片上传

前端代码:(执行文件切片循环上传并最后发起结束合并请求)

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
};

以上就是文件切片上传,支持多人同时操作。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值