js 大文件分割/分片上传
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>uploadFile</title>
<style></style>
</head>
<body>
<input type="file" id="file" multiple />
<br />
<br />
<button id="btn">上传</button>
<script>
var uploadFile;
document.querySelector("#file").addEventListener(
"change",
(e) => {
var files = e.target.files;
if (!files.length) return;
uploadFile = new CutFileAndUpload({
files,
apiUpload: (fileData) => {
//接口请求 返回当前文件数据
/**
* fileData = {
file: file, //当前文件
succeed: 0, //已经上传的片数
shardSize: this.size, //以2MB为一个分片
shardCount: 0, //总片数
start: 0, //截取开始位置
end: 0, //截取结束位置
}
*/
//构造一个表单 表单字段根据后端接口而定
let fdata = new FormData();
//计算切割文件单个分片
let base64 = fileData.file.slice(fileData.start, fileData.end);
// fdata.append("base64", base64, fileData.file.name);
// fdata.append("name", fileData.file.name);
// fdata.append("total", fileData.shardCount); //总片数
// fdata.append("numbers", fileData.succeed + 1); //当前是第几片
//接口请求
setTimeout(() => {
//更新文件数据
uploadFile.updateFileData();
}, 2000);
},
progress: (progress, total) => {
//progress 当前文件进度百分比
//total 总进度百分比
console.log(progress, total);
},
success: () => {
//上传成功回调
console.log("全部上传完成");
e.target.value = "";
},
});
},
false
);
document.querySelector("#btn").addEventListener(
"click",
() => {
uploadFile.uploadFile();
},
false
);
/**
*
* @param {*} options
*/
function CutFileAndUpload(options) {
this.files = options.files || []; //要上传的文件列表
this.progress = options.progress; //上传进度
this.success = options.success; //成功回调
this.apiUpload = options.apiUpload;
this.fileArr = []; //文件列表切割后的文件数据
this.fileIndex = 0; //上传到第几个文件
this.size = 2 * 1024 * 1024; //分片单位 以2MB为一个分片
this.uploading = false; //上传状态
this.cutFile();
}
CutFileAndUpload.prototype = {
constructor: CutFileAndUpload,
cutFile() {
var files = this.files;
if (!files.length) {
console.log("请选择要上传的文件");
return;
}
for (var i = 0; i < files.length; i++) {
var file = files[i];
let fileData = {
file: file,
succeed: 0, //已经上传的片数
shardSize: this.size, //分片单位
shardCount: 0, //总片数
start: 0, //截取开始位置
end: 0, //截取结束位置
};
fileData.shardCount = Math.ceil(
fileData.file.size / fileData.shardSize
); //总片数
this.fileArr.push(fileData);
}
},
uploadFile() {
if (!this.fileArr.length) {
console.log("请选择要上传的文件");
return;
}
var fileData = this.fileArr[this.fileIndex];
//计算每一片的起始与结束位置
fileData.start = fileData.succeed * fileData.shardSize;
fileData.end = Math.min(
fileData.file.size,
fileData.start + fileData.shardSize
);
//计算文件单个分片
// let base64 = fileData.file.slice(fileData.start, fileData.end);
// console.log(fileData);
this.uploading = true;
//接口请求
this.apiUpload && this.apiUpload(fileData);
},
updateFileData() {
//更新文件数据
var fileData = this.fileArr[this.fileIndex];
fileData.succeed++;
var progress = parseInt(
(fileData.succeed / fileData.shardCount) * 100
);
var total;
if (fileData.succeed === fileData.shardCount) {
//单个文件上传完成
this.fileIndex++;
total = parseInt((this.fileIndex / this.fileArr.length) * 100);
this.progress && this.progress(progress, total);
if (this.fileIndex == this.fileArr.length) {
//列表的全部文件上传完成
this.uploading = false;
this.fileIndex = 0;
this.fileArr = [];
this.success && this.success();
} else {
this.uploadFile();
}
} else {
total = parseInt((this.fileIndex / this.fileArr.length) * 100);
this.progress && this.progress(progress, total);
this.uploadFile();
}
},
};
</script>
</body>
</html>
参考文章:http://blog.ncmem.com/wordpress/2023/11/14/js-%e5%a4%a7%e6%96%87%e4%bb%b6%e5%88%86%e5%89%b2-%e5%88%86%e7%89%87%e4%b8%8a%e4%bc%a0/
欢迎入群一起讨论
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
2019-11-14 Web上传超大文件解决方案
2019-11-14 Flash上传超大文件解决方案
2019-11-14 B/S上传超大文件解决方案
2019-11-14 外网上传超大文件解决方案
2019-11-14 内网上传超大文件解决方案
2019-11-14 前端上传超大文件解决方案
2019-11-14 js上传超大文件解决方案