Vue.Js及Java实现⽂件分⽚上传代码实例
说明
代码从项⽬中剥离修改,未经测试,仅提供思路。
前端
upload(file) {
//从后台获取已经上传的⽂件分⽚数
getIdx(md5)
.then(function(res) {
let retry = 3;
uploadPart(retry, file, res.data);
})
.
catch();
}
uploadPart(retry, file, idx) {
//设置分⽚⼤⼩(单位Byte)
let bufferLength = 1024 * 1024 * 5;
//计算开始的切割点,idx是上传成功的分⽚数,未上传过⽂件则开始点为0
let start = idx * bufferLength;
//全部上传完毕或重试次数⽤完则退出
if(start>=file.size || retry<=0) return;
//计算分割的位置
let end = start + bufferLength;
/
/如果分割点超出⽂件⼤⼩,回退分割点
if (end > file.size) {end = fileSize;}
//切割⽂件
var chunk = file.slice(start, end);
//创建 formData 对象并添加数据
let formData = new FormData();
formData.set("file", chunk);
//如果是第⼀次上传,连同⽂件块数量也上传
if (start == 0) {
//计算⽂件切⽚总数,向上取整
let chunkNum = il(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);
});
},
⽂件分⽚上传的前端关键代码只有⼀句:
//切割⽂件
var chunk = file.slice(start, end);
通过slice⽅法来切割⽂件,然后⽂件上传的流程视业务和具体技术⽽定,此处是使⽤axios发送请求,⽤递归调⽤上传⽂件块。
需要注意的是,Blob.slice(start, end),⽂件块包含start指向的字节,⽽不包含end指向的字节,在使⽤时要注意Blob的边界。mozilla对slice的说明
后端
/**合并⽂件的实际操作*/
public static void doMergeFiles(String outFile, String[] files) {
//设置缓存⼤⼩
int BUFSIZE = 1024 * 1024;
//排序。⽂件后缀名是⽂件的顺序。
Arrays.sort(files);
//输出流
FileChannel outChannel = null;
//标记最后的⼀个⽂件
String lastFlag = files[files.length-1];
try {
outChannel = new FileOutputStream(outFile).getChannel();
//遍历⽂件列表
for(String f : files){
//最后⼀块⽂件⽤真实⼤⼩设置缓存,避免⾃动填充数据造成的md5不⼀致
if(lastFlag.equals(f)){
File last = new File(f);
BUFSIZE = (int) last.length();//获取⽂件的⼤⼩并设置成缓存的⼤⼩
}
FileChannel fc = new FileInputStream(f).getChannel();
//⽤ByteBuffer创建缓存
ByteBuffer bb = ByteBuffer.allocate(BUFSIZE);
ad(bb) != -1){//把数据读到缓存
bb.flip();//重置游标
outChannel.write(bb);//写⼊数据
前端大文件上传解决方案bb.clear();//清空数据
}
fc.close();//关闭流
}
} catch (IOException ioe) {
ioe.printStackTrace();
} finally {
try {if (outChannel != null) {outChannel.close();}} catch (IOException ignore) {}
}
}
后端的关键是合并⽂件,当上传完最后⼀块⽂件就进⾏⽂件的合并。使⽤ByteBuffer缓存,使⽤FileChannel进⾏⽂件的读写完成合并操作。在保存⽂件时,⽂件名取⼀致,⽂件的后缀名则取⽂件块的顺序,⽐如第⼀块⽂件是“xxx.01”,第10块
是“xxx.10”,注意,个位数前⾯要补“0”,这样可以直接⽤Array.sort()进⾏排序。
为提⾼性能,可以适当设置缓存⼤⼩,可以边上传⽂件边合并,不必等到⽂件都上传了才合并。
拓展
此处的⽂件上传是⼀次上传⼀⽚,上传成功才开始上传下⼀⽚。如果前端不是使⽤javascript,能开启使⽤多线程的话,可以改成同时上传多⽚⽂件提⾼上传速度。已经上传的⽂件分⽚⽤bitmap存储,上传⽂件前,从后台获取已上传的⽂件分⽚的bitmap数据然后解析,多线程处理未上传的⽂件分⽚。
以上就是本⽂的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论