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 = 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数据然后解析,多线程处理未上传的文件分片。

以上是 Vue.Js及Java实现文件分片上传代码实例 的全部内容, 来源链接: utcz.com/z/311911.html

回到顶部