大文件上传切片抽样MD5值得校验
前言
大文件上传并使用抽样算法取出部分文件生成MD5值
当这个问题抛出来,我就已经开始慌了,求带马跌,文件MD5值咋生成,以及抽样又是什么

抽样算法可以参考
这边先模拟一下,先将文件给切分成想要得文件大小,切分成每片为10M大小得文件
代码
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public static void main(String[] args) {
//调用cutFile()函数 传人参数分别为 (原大文件,切割后存放的小文件的路径,切割规定的内存大小)
// 源文件
cutFile("C:\\Users\\admin\\Desktop\\2.svs",
// 切片后存储得文件路径
"D:\\ProjectFile\\JavaProject\\staitech-openslide\\src\\test\\java\\cn\\staitech\\openslide\\filetest03",
// 每片文件得大小10M
1024 * 1024 * 10);
}
private static void cutFile(String src, String endsrc, int num) {
double nums = Math.ceil(num);
FileInputStream fis = null;
File file = null;
try {
fis = new FileInputStream(src);
file = new File(src);
//创建规定大小的byte数组
byte[] b = new byte[(int) num];
int len = 0;
//name为以后的小文件命名做准备
int name = 1;
//遍历将大文件读入byte数组中,当byte数组读满后写入对应的小文件中
while ((len = fis.read(b)) != -1) {
//分别找到原大文件的文件名和文件类型,为下面的小文件命名做准备
String name2 = file.getName();
int lastIndexOf = name2.lastIndexOf(".");
String substring = name2.substring(0, lastIndexOf);
String substring2 = name2.substring(lastIndexOf, name2.length());
FileOutputStream fos = new FileOutputStream(endsrc + "\\\\"+ substring + "-" + name + substring2);
//将byte数组写入对应的小文件中
fos.write(b, 0, len);
//结束资源
fos.close();
name++;
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fis != null) {
//结束资源
fis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
切割完成之后,遍历文件夹,将文件取出进行操作
我这边是取得文件得第一个和最后一个切片得全部内容,以及中间文件得前后各100KB,大家可以按照自己得需求进行截取文件流,使用RandomAccessFile.seek()方法可以指定写入文件。然后以此生成一个完整得文件
public static void main(String[] args) throws IOException {
// 被遍历得文件夹
String path = "D:\\ProjectFile\\JavaProject\\staitech-openslide\\src\\test\\java\\cn\\staitech\\openslide\\filetest03"; //要遍历的路径
// md5得临时文件
File pathMd5 = new File(
"D:\\ProjectFile\\JavaProject\\staitech-openslide\\src\\test\\java\\cn\\staitech\\openslide\\aaa.txt");
// 创建临时文件
if (!pathMd5.isFile() && !pathMd5.exists()) {
pathMd5.createNewFile();
System.out.println("创建文件成功");
}
// 循环取出文件下得文件并存储在hasmap中
HashMap<Integer, File> fileMap = new HashMap<>();
File file = new File(path); //获取其file对象
File[] fs = file.listFiles(); //遍历path下的文件和目录,放在File数组中
int i = 0;
for (File f : fs) {
if (!f.isDirectory()) { //若非目录(即文件),则打印
fileMap.put(i, f);
}
i++;
}
// 计算每个切片被分割成多少块
int cycles = (1024 * 1024 * 10) / (1024 * 4 * 10);
for (int g = 0; g <= fs.length - 1; g++) {
// 文件每块切割得大小 40KB
byte[] buffer = new byte[1024 * 4 * 10];
int len = 0;
File f = fileMap.get(g);
// 当前被遍历得文件
FileInputStream fis = new FileInputStream(f);
// 将生成MD5值得文件转化成Random流,以便完成在指定位置进行插入
RandomAccessFile rafMd5 = new RandomAccessFile(pathMd5, "rw");
// 定义变量,用于记录当前切片每块得编号
int num = 0;
while ((len = fis.read(buffer)) != -1) {
// 判断,第一个切片全部写入到文件中
// RandomAccessFile.seek()用于指定写入文件得位置,然后再使用write进行写入操作
if (g == 0) {
rafMd5.seek((long) num * len);
rafMd5.write(buffer, 0, len);
// 最后一个文件也进行全部写入
} else if (g == (fs.length - 1)) {
if (len < 1024 * 4 * 10) {
int top = 1024 * 1024 * 10 + 1024 * 50 * 2 * (g - 1);
rafMd5.seek(top + num * 1024 * 4 * 10);
} else {
int top = 1024 * 1024 * 10 + 1024 * 50 * 2 * (g - 1);
rafMd5.seek(top + (long) num * len);
}
rafMd5.write(buffer, 0, len);
} else {
/** 将10M文件以40KB进行读取
* num用来记录当前读取得块数,cycles用来记录总数
* 文件写入只取出10M文件中得前100KB和后100KB
*/
if (num == 0) {
rafMd5.seek(1024 * 1024 * 10 + 1024L * 50 * 2 * (g - 1));
rafMd5.write(buffer, 0, len);
}
if (num == 1) {
rafMd5.seek(1024 * 1024 * 10 + 1024L * 50 * 2 * (g - 1) + 1024 * 40);
rafMd5.write(buffer, 0, 1024 * 10);
}
if (num == cycles - 1) {
rafMd5.seek(1024 * 1024 * 10 + 1024L * 50 * 2 * (g - 1) + 1024 * 60);
rafMd5.write(buffer, 0, len);
}
if (num == cycles - 2) {
rafMd5.seek(1024 * 1024 * 10 + 1024L * 50 * 2 * (g - 1) + 1024 * 50);
rafMd5.write(buffer, 1024 * 30, 1024 * 10);
}
}
num++;
}
}
// 获取文件地址,并将其转化为FileInputStream
FileInputStream inputStream1 = new FileInputStream(ResourceUtils.getFile((pathMd5.getAbsolutePath())));
// 使用DigestUtils.md5DigestAsHex将流转化成md5值
String tMd5 = DigestUtils.md5DigestAsHex(inputStream1);
System.out.println(tMd5);
// 最终可以与前端传入得MD5进行做对比,然后执行逻辑操作
/**
* 逻辑
*/
// 进行完逻辑处理之后,删除临时文件
if (pathMd5.isFile() && pathMd5.exists()) {
if (pathMd5.delete()) {
System.out.println("删除文件" + pathMd5 + "成功!");
} else {
System.out.println("删除文件" + pathMd5 + "失败!");
}
}
}
结语:
当然,这只是模拟实现,正常情况下切片应该是前端通过接口传值传过来得,如果还需要自己进行分割文件,效率会大打折扣,也没有这个必要,要不然你猜他为什么叫做大文件切片上传呢。


浙公网安备 33010602011771号