大文件上传切片抽样MD5值得校验

前言

大文件上传并使用抽样算法取出部分文件生成MD5值

当这个问题抛出来,我就已经开始慌了,求带马跌,文件MD5值咋生成,以及抽样又是什么

 

没办法兵来将挡,水来土掩,不多废话,上代码,开撸,奥里给!!!

抽样算法可以参考谈谈前端大文件分片上传 - 掘金 (juejin.cn)

这边先模拟一下,先将文件给切分成想要得文件大小,切分成每片为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 + "失败!");
        }
        
    }
}

  

结语

当然,这只是模拟实现,正常情况下切片应该是前端通过接口传值传过来得,如果还需要自己进行分割文件,效率会大打折扣,也没有这个必要,要不然你猜他为什么叫做大文件切片上传呢。

 

posted @ 2022-12-16 15:54  Μikey  阅读(480)  评论(0)    收藏  举报