在项目中如果存在大文件的上传或者下载功能,因为用户的网络或者其他各种问题,导致文件上传了一部分或者下载了一部分之后,无法继续了。这个时候就需要使用断点续传,再下次上传或者下载时,继续从上次失败的地方开始。
实现思路:将大文件分块进行上传,一个文件大小为1GB,我们分成10份,这样如果在上传的时候在第五份失败了,那么我们下次就从第五份开始。下载同理。
断点续传分为两部分:分块,合并。
分块
分块就是将文件分成一块一块的。
合并
将分块的文件合并成一个文件。
测试代码如下
package com.xuehceng.media;
import io.minio.GetObjectArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.RemoveObjectArgs;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import org.junit.jupiter.api.Test;
import java.io.*;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
public class BigFileTest {
// 分快
@Test
void testChunk() throws IOException {
// 源文件
File file = new File("E:\\1.mp4");
// 分块的文件目录
String chunkPath = "E:\\chunk\\";
// 每一块的大小
int chunkSize = 1024 * 1024 * 5; //5M
// 分成多少块(文件大小/块的大小)向上取整
int chunkNum = (int) Math.ceil(file.length() * 1.0 / chunkSize);
// 读取文件的内容为随机访问文件流
RandomAccessFile ran_r = new RandomAccessFile(file, "r");
// 将读取的文件写入到分块的文件目录中并且进行分块
byte[] bytes = new byte[1024]; //缓冲区1M
/**
* 读1MB,写一个MB,如此不断循环,写完一个文件块,for循环继续,直到读完所有文件块
*
*/
for (int i = 0; i < chunkNum; i++) { //根据多少块遍历多少次,每一次循环都是写入一块文件
// 创建分块文件,文件地址为chunkPath+i
File chunkFile = new File(chunkPath + i);
if (chunkFile.exists()) {
chunkFile.delete();
}
boolean newFile = chunkFile.createNewFile();
if (newFile) {
RandomAccessFile ran_rw = new RandomAccessFile(chunkFile, "rw");
int len = -1; //读取的字节数
while ((len = ran_r.read(bytes)) != -1) { //r.read()每次返回的都是读取的字节数,-1表示读完了
// 写入文件块
ran_rw.write(bytes, 0, len); //表示从0开始写,len表示写入的字节数
if (chunkSize == ran_rw.length()) {
break;
}
}
}
}
}
// 合并
@Test
void testMerge() throws IOException {
/**
* 读取文件块,将文件块进行排序,然后进行合并
*/
String chunkPath = "E:\\chunk\\"; //分块文件目录
//获取分块文件并排序
File[] chunkFiles = new File(chunkPath).listFiles();
Arrays.sort(chunkFiles, new Comparator<File>() {
@Override
public int compare(File o1, File o2) { //排序规则 升序
return Integer.parseInt(o1.getName()) - Integer.parseInt(o2.getName());
}
});
// 创建合并文件
File file = new File("E:\\2.mp4");
boolean newFile = file.createNewFile(); //创建一个新的空文件
//用于写文件的流
RandomAccessFile raf_write = new RandomAccessFile(file, "rw");
if (newFile) { //文件创建成功开始写
byte[] bytes = new byte[1024]; //创建缓冲区
// 合并文件
for (File chunkFile : chunkFiles) {
// 遍历一次读取一个文件块,将读取到的文件块写入合并文件
int len = -1;
RandomAccessFile r = new RandomAccessFile(chunkFile, "r");
while ((len = r.read(bytes)) != -1) {
raf_write.write(bytes, 0, len);
}
r.close();
}
raf_write.close();
}
}
}
531

被折叠的 条评论
为什么被折叠?



