Vue.Js及Java实现文件分片上传代码实例
说明
代码从项目中剥离修改,未经测试,仅提供思路。
前端
upload(file){
//从后台获取已经上传的文件分片数
getIdx(md5)
.then(function(res){
letretry=3;
uploadPart(retry,file,res.data);
})
.catch();
}
uploadPart(retry,file,idx){
//设置分片大小(单位Byte)
letbufferLength=1024*1024*5;
//计算开始的切割点,idx是上传成功的分片数,未上传过文件则开始点为0
letstart=idx*bufferLength;
//全部上传完毕或重试次数用完则退出
if(start>=file.size||retry<=0)return;
//计算分割的位置
letend=start+bufferLength;
//如果分割点超出文件大小,回退分割点
if(end>file.size){end=fileSize;}
//切割文件
varchunk=file.slice(start,end);
//创建formData对象并添加数据
letformData=newFormData();
formData.set("file",chunk);
//如果是第一次上传,连同文件块数量也上传
if(start==0){
//计算文件切片总数,向上取整
letchunkNum=Math.ceil(file.size/bufferLength);
formData.set("total",chunkNum);
}
//上传文件的api,此处使用axios发送请求
doUpload(formData)
//发送成功,则上传下一片,递归调用方法
.then(function(){
retry=xx;//刷新重试次数
uploadPart(retry,file,++idx);
})
//发送失败
.catch(function(){
retry--;//重试次数减一
//重试上传这一片
uploadPart(retry,file,idx);
});
},
文件分片上传的前端关键代码只有一句:
//切割文件
varchunk=file.slice(start,end);
通过slice方法来切割文件,然后文件上传的流程视业务和具体技术而定,此处是使用axios发送请求,用递归调用上传文件块。
需要注意的是,Blob.slice(start,end),文件块包含start指向的字节,而不包含end指向的字节,在使用时要注意Blob的边界。
mozilla对slice的说明
后端
/**合并文件的实际操作*/
publicstaticvoiddoMergeFiles(StringoutFile,String[]files){
//设置缓存大小
intBUFSIZE=1024*1024;
//排序。文件后缀名是文件的顺序。
Arrays.sort(files);
//输出流
FileChanneloutChannel=null;
//标记最后的一个文件
StringlastFlag=files[files.length-1];
try{
outChannel=newFileOutputStream(outFile).getChannel();
//遍历文件列表
for(Stringf:files){
//最后一块文件用真实大小设置缓存,避免自动填充数据造成的md5不一致
if(lastFlag.equals(f)){
Filelast=newFile(f);
BUFSIZE=(int)last.length();//获取文件的大小并设置成缓存的大小
}
FileChannelfc=newFileInputStream(f).getChannel();
//用ByteBuffer创建缓存
ByteBufferbb=ByteBuffer.allocate(BUFSIZE);
while(fc.read(bb)!=-1){//把数据读到缓存
bb.flip();//重置游标
outChannel.write(bb);//写入数据
bb.clear();//清空数据
}
fc.close();//关闭流
}
}catch(IOExceptionioe){
ioe.printStackTrace();
}finally{
try{if(outChannel!=null){outChannel.close();}}catch(IOExceptionignore){}
}
}
后端的关键是合并文件,当上传完最后一块文件就进行文件的合并。使用ByteBuffer缓存,使用FileChannel进行文件的读写完成合并操作。在保存文件时,文件名取一致,文件的后缀名则取文件块的顺序,比如第一块文件是“xxx.01”,第10块是“xxx.10”,注意,个位数前面要补“0”,这样可以直接用Array.sort()进行排序。
为提高性能,可以适当设置缓存大小,可以边上传文件边合并,不必等到文件都上传了才合并。
拓展
此处的文件上传是一次上传一片,上传成功才开始上传下一片。如果前端不是使用javascript,能开启使用多线程的话,可以改成同时上传多片文件提高上传速度。已经上传的文件分片用bitmap存储,上传文件前,从后台获取已上传的文件分片的bitmap数据然后解析,多线程处理未上传的文件分片。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。