Vue.Js及Java实现文件分片上传代码实例
程序员文章站
2023-02-20 21:51:09
说明代码从项目中剥离修改,未经测试,仅提供思路。前端upload(file) { //从后台获取已经上传的文件分片数 getidx(md5) .then(function(res) { let...
说明
代码从项目中剥离修改,未经测试,仅提供思路。
前端
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 = 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); }); },
文件分片上传的前端关键代码只有一句:
//切割文件
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); while(fc.read(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数据然后解析,多线程处理未上传的文件分片。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。