分片上传、断点续传
1、分片上传HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h2>分片上传</h2>
<p>
选择文件: <input type="file" id="file" name="file" />
</p>
<p>
<input type="button" value="提交" onclick="commit()" />
</p>
</body>
<script type="text/javascript">
//每个文件切片大小定为1M(1024*1024字节)(需要跟服务器协商好).
var BYTES_PER_SLICE = 1<<20;
// 已发送的数量
var hasSendNum = 0;
// 总切片数
var totalSlices;
// 提交方法
function commit() {
// 拿出选中的第一个文件
var file = document.getElementById("file").files[0];
// 文件的总字节数
var totalSize = file.size;
// 当前片数
var index = 0;
// 分片的开始、结束(不含)
var start,end;
// 文件名
var fileName = file.name;
// 初始化已发送数量为0
hasSendNum = 0;
// 计算文件切片总数(向上取整)
totalSlices = Math.ceil(file.size / BYTES_PER_SLICE);
// 不断循环将切片上传
while(index < totalSlices) {
start = index*BYTES_PER_SLICE;
end = start + BYTES_PER_SLICE;
var slice =file.slice(start,end);//切割文件
uploadFile(slice, index++,fileName);
console.log("size:",BYTES_PER_SLICE);
console.log("num:",hasSendNum);
console.log("slices:",totalSlices);
console.log("start:",start) ;
console.log("end:",end) ;
console.log("index:",index) ;
console.log("-------------");
}
}
//上传文件
function uploadFile(slice, index,fileName) {
var retry = 1;
var formDate = new FormData();
formDate.append("slice", slice);
formDate.append("fileName",fileName);
formDate.append("index",index);
var xhr = new XMLHttpRequest();
xhr.open('POST', 'sliceUpload', true);
//false指同步上传,因为我的服务器内存较小,选择同步,如果追求速度,可以选择 //ture,异步上传
xhr.onreadystatechange = ()=>uploadCallBack(xhr,slice,index,fileName);
xhr.send(formDate);
}
/**
* @desc 上传回调
* @param xhr
*/
function uploadCallBack(xhr,slice,index,fileName) {
if(xhr.readyState==4) {
if(xhr.status==200) {
if(xhr.responseText==1) {
hasSendNum++;
console.log("第"+index+"片,完成度"+parseInt(hasSendNum/totalSlices*100)+"%");
if(hasSendNum==totalSlices) {
console.log("上传完毕");
}
}
} else {
console.log("上传失败,重试##################################");
// 重试
//uploadFile(slice, index,fileName);
}
}
}
</script>
</html>
2、后端代码
private final int BYTES_PER_SLICE = 1<<20;
@RequestMapping(value="sliceUpload",method= RequestMethod.POST)
@ResponseBody
public int upload(@RequestParam("slice")MultipartFile slice,String fileName,int index) {
int result = 0;
if(slice.isEmpty()){
return 0;
}
int size = (int) slice.getSize();
System.out.println(fileName + "-->" + size);
String path = "e:/test" ;
File dest = new File(path + "/" + fileName);
RandomAccessFile randomAccessFile = null;
if(!dest.getParentFile().exists()){ //判断文件父目录是否存在
dest.getParentFile().mkdir();
}
try {
randomAccessFile = new RandomAccessFile(dest,"rw");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
try {
byte[] bytes = slice.getBytes(); //保存文件
randomAccessFile.seek(index*BYTES_PER_SLICE);
randomAccessFile.write(bytes);
result = 1;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
try {
randomAccessFile.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
3、显示进度条,网速HTML(进度条是每个分片的,待调整)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<progress id="progressBar" value="0" max="100" style="width: 300px;"></progress>
<span id="percentage"></span><span id="time"></span>
<br /><br />
<input type="file" id="file" name="myfile" />
<input type="button" onclick="commit()" value="上传" />
<input type="button" onclick="cancleUploadFile()" value="取消" />
</body>
<script type="text/javascript">
//每个文件切片大小定为1M(1024*1024字节)(需要跟服务器协商好).
var BYTES_PER_SLICE = 1<<20;
// 已发送的数量
var hasSendNum = 0;
// 总切片数
var totalSlices;
// 提交方法
function commit() {
// 拿出选中的第一个文件
var file = document.getElementById("file").files[0];
// 文件的总字节数
var totalSize = file.size;
// 当前片数
var index = 0;
// 分片的开始、结束(不含)
var start,end;
// 文件名
var fileName = file.name;
// 初始化已发送数量为0
hasSendNum = 0;
var ot;//
var oloaded;
// 计算文件切片总数(向上取整)
totalSlices = Math.ceil(file.size / BYTES_PER_SLICE);
// 不断循环将切片上传
while(index < totalSlices) {
start = index*BYTES_PER_SLICE;
end = start + BYTES_PER_SLICE;
var slice =file.slice(start,end);//切割文件
uploadFile(slice, index++,fileName);
console.log("size:",BYTES_PER_SLICE);
console.log("num:",hasSendNum);
console.log("slices:",totalSlices);
console.log("start:",start) ;
console.log("end:",end) ;
console.log("index:",index) ;
console.log("-------------");
}
}
//上传文件
function uploadFile(slice, index,fileName) {
var retry = 1;
var formDate = new FormData();
formDate.append("slice", slice);
formDate.append("fileName",fileName);
formDate.append("index",index);
var xhr = new XMLHttpRequest();
xhr.open('POST', 'sliceUpload', true);
//false指同步上传,因为我的服务器内存较小,选择同步,如果追求速度,可以选择 //ture,异步上传
//xhr.onload = uploadComplete; //请求完成
//xhr.onerror = uploadFailed; //请求失败
xhr.onreadystatechange = ()=>uploadCallBack(xhr,slice,index,fileName);//上传回调
xhr.upload.onprogress = progressFunction;//【上传进度调用方法实现】
xhr.upload.onloadstart = function(){//上传开始执行方法
ot = new Date().getTime(); //设置上传开始时间
oloaded = 0;//设置上传开始时,以上传的文件大小为0
};
xhr.send(formDate);
}
/**
* @desc 上传回调
* @param xhr
*/
function uploadCallBack(xhr,slice,index,fileName) {
if(xhr.readyState==4) {
if(xhr.status==200) {
if(xhr.responseText==1) {
hasSendNum++;
console.log("第"+index+"片,完成度"+parseInt(hasSendNum/totalSlices*100)+"%");
if(hasSendNum==totalSlices) {
console.log("上传完毕");
}
}
} else {
console.log("上传失败,重试##################################");
// 重试
//uploadFile(slice, index,fileName);
}
}
}
//上传进度实现方法,上传过程中会频繁调用该方法
function progressFunction(evt) {
var progressBar = document.getElementById("progressBar");
var percentageDiv = document.getElementById("percentage");
// event.total是需要传输的总字节,event.loaded是已经传输的字节。如果event.lengthComputable不为真,则event.total等于0
if (evt.lengthComputable) {//
progressBar.max = evt.total;
progressBar.value = evt.loaded;
percentageDiv.innerHTML = Math.round(evt.loaded / evt.total * 100) + "%";
}
var time = document.getElementById("time");
var nt = new Date().getTime();//获取当前时间
var pertime = (nt-ot)/1000; //计算出上次调用该方法时到现在的时间差,单位为s
ot = new Date().getTime(); //重新赋值时间,用于下次计算
var perload = evt.loaded - oloaded; //计算该分段上传的文件大小,单位b
oloaded = evt.loaded;//重新赋值已上传文件大小,用以下次计算
//上传速度计算
var speed = perload/pertime;//单位b/s
var bspeed = speed;
var units = 'b/s';//单位名称
if(speed/1024>1){
speed = speed/1024;
units = 'k/s';
}
if(speed/1024>1){
speed = speed/1024;
units = 'M/s';
}
speed = speed.toFixed(1);
//剩余时间
var resttime = ((evt.total-evt.loaded)/bspeed).toFixed(1);
time.innerHTML = ',速度:'+speed+units+',剩余时间:'+resttime+'s';
if(bspeed==0)
time.innerHTML = '上传已取消';
}
//上传成功响应
function uploadComplete(evt) {
//服务断接收完文件返回的结果
// alert(evt.target.responseText);
alert("上传成功!");
}
//上传失败
function uploadFailed(evt) {
alert("上传失败!");
}
//取消上传
function cancleUploadFile(){
xhr.abort();
}
</script>
</html><!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<progress id="progressBar" value="0" max="100" style="width: 300px;"></progress>
<span id="percentage"></span><span id="time"></span>
<br /><br />
<input type="file" id="file" name="myfile" />
<input type="button" onclick="commit()" value="上传" />
<input type="button" onclick="cancleUploadFile()" value="取消" />
</body>
<script type="text/javascript">
//每个文件切片大小定为1M(1024*1024字节)(需要跟服务器协商好).
var BYTES_PER_SLICE = 1<<20;
// 已发送的数量
var hasSendNum = 0;
// 总切片数
var totalSlices;
// 提交方法
function commit() {
// 拿出选中的第一个文件
var file = document.getElementById("file").files[0];
// 文件的总字节数
var totalSize = file.size;
// 当前片数
var index = 0;
// 分片的开始、结束(不含)
var start,end;
// 文件名
var fileName = file.name;
// 初始化已发送数量为0
hasSendNum = 0;
var ot;//
var oloaded;
// 计算文件切片总数(向上取整)
totalSlices = Math.ceil(file.size / BYTES_PER_SLICE);
// 不断循环将切片上传
while(index < totalSlices) {
start = index*BYTES_PER_SLICE;
end = start + BYTES_PER_SLICE;
var slice =file.slice(start,end);//切割文件
uploadFile(slice, index++,fileName);
console.log("size:",BYTES_PER_SLICE);
console.log("num:",hasSendNum);
console.log("slices:",totalSlices);
console.log("start:",start) ;
console.log("end:",end) ;
console.log("index:",index) ;
console.log("-------------");
}
}
//上传文件
function uploadFile(slice, index,fileName) {
var retry = 1;
var formDate = new FormData();
formDate.append("slice", slice);
formDate.append("fileName",fileName);
formDate.append("index",index);
var xhr = new XMLHttpRequest();
xhr.open('POST', 'sliceUpload', true);
//false指同步上传,因为我的服务器内存较小,选择同步,如果追求速度,可以选择 //ture,异步上传
//xhr.onload = uploadComplete; //请求完成
//xhr.onerror = uploadFailed; //请求失败
xhr.onreadystatechange = ()=>uploadCallBack(xhr,slice,index,fileName);//上传回调
xhr.upload.onprogress = progressFunction;//【上传进度调用方法实现】
xhr.upload.onloadstart = function(){//上传开始执行方法
ot = new Date().getTime(); //设置上传开始时间
oloaded = 0;//设置上传开始时,以上传的文件大小为0
};
xhr.send(formDate);
}
/**
* @desc 上传回调
* @param xhr
*/
function uploadCallBack(xhr,slice,index,fileName) {
if(xhr.readyState==4) {
if(xhr.status==200) {
if(xhr.responseText==1) {
hasSendNum++;
console.log("第"+index+"片,完成度"+parseInt(hasSendNum/totalSlices*100)+"%");
if(hasSendNum==totalSlices) {
console.log("上传完毕");
}
}
} else {
console.log("上传失败,重试##################################");
// 重试
//uploadFile(slice, index,fileName);
}
}
}
//上传进度实现方法,上传过程中会频繁调用该方法
function progressFunction(evt) {
var progressBar = document.getElementById("progressBar");
var percentageDiv = document.getElementById("percentage");
// event.total是需要传输的总字节,event.loaded是已经传输的字节。如果event.lengthComputable不为真,则event.total等于0
if (evt.lengthComputable) {//
progressBar.max = evt.total;
progressBar.value = evt.loaded;
percentageDiv.innerHTML = Math.round(evt.loaded / evt.total * 100) + "%";
}
var time = document.getElementById("time");
var nt = new Date().getTime();//获取当前时间
var pertime = (nt-ot)/1000; //计算出上次调用该方法时到现在的时间差,单位为s
ot = new Date().getTime(); //重新赋值时间,用于下次计算
var perload = evt.loaded - oloaded; //计算该分段上传的文件大小,单位b
oloaded = evt.loaded;//重新赋值已上传文件大小,用以下次计算
//上传速度计算
var speed = perload/pertime;//单位b/s
var bspeed = speed;
var units = 'b/s';//单位名称
if(speed/1024>1){
speed = speed/1024;
units = 'k/s';
}
if(speed/1024>1){
speed = speed/1024;
units = 'M/s';
}
speed = speed.toFixed(1);
//剩余时间
var resttime = ((evt.total-evt.loaded)/bspeed).toFixed(1);
time.innerHTML = ',速度:'+speed+units+',剩余时间:'+resttime+'s';
if(bspeed==0)
time.innerHTML = '上传已取消';
}
//上传成功响应
function uploadComplete(evt) {
//服务断接收完文件返回的结果
// alert(evt.target.responseText);
alert("上传成功!");
}
//上传失败
function uploadFailed(evt) {
alert("上传失败!");
}
//取消上传
function cancleUploadFile(){
xhr.abort();
}
</script>
</html>