大文件断点续传的分块和合并方法

118 阅读2分钟
/**
 * @author Maple
 * @version 1.0
 * @description 测试大文件上传方法
 * @date 2023/3/29 15:20
 */
public class BigFileTest {
    //分块测试
    @Test
    public void testChunk() throws IOException {
        //要分块文件的地址,要合并到的地址,判断分块文件是否存在,不存在创建文件
        //创建要分块的大小,分块的数量,缓存区大小(来存放每次读的数据),RandomAccessFile写流
        //通过for遍历分块数量来写入数据,在for遍历中通过给分块文件名称通过+i来生成唯一的文件名
        //如果文件名已经存在,就先删除,通过while一边读一边写。
        // 当写流中的文件大于等于分块大小的时候跳出while循环,继续下一次for循环。

        File sourceFile = new File("D:\develop\chunk\001-ChatGPT背景介绍.mp4");
        String chunkPath = "D:\develop\chunk_target\";
        if(!sourceFile.exists()){
            sourceFile.mkdirs();
        }
        //分块大小
        long  chunkSize = 1024 * 1024 * 1;
        //分块数量
        long chunkNum  = (long) Math.ceil(sourceFile.length() * 1.0 / chunkSize);
        System.out.println("分块总数:"+chunkNum);
        //缓冲区大小
        byte[] bytes = new byte[1024];
        //使用RandomAccessFile访问文件
        RandomAccessFile raf_read = new RandomAccessFile(sourceFile, "r");
        //分块
        for (int i = 0; i < chunkNum ; i++) {
            //创建分块文件
            File file = new File(chunkPath + i);
            if(file.exists()){
                file.delete();
            }
            boolean newFile = file.createNewFile();
            if(newFile){
                //向分块文件中写数据
                RandomAccessFile raf_write = new RandomAccessFile(file, "rw");
                int len = -1;
                while ((len = raf_read.read(bytes)) != -1){
                    raf_write.write(bytes,0,len);
                    if(file.length() >= chunkSize){
                        break;
                    }
                }
                raf_write.close();
                System.out.println("完成分块"+i);
            }
        }
        raf_read.close();
    }
    //将分块进行合并
    @Test
    public void testMerge() throws IOException {
        //分块文件地址,合并文件地址,获取分块文件,将数组转换为list
        //对分块list进行文件名的排序,对list进行for遍历,定义len和byte缓冲区,创建RandomAccessFile写流
        //创建RandomAccessFile读流,通过while一边读一边写,关闭读流,关闭写流。
        //通过两个地址的md5值进行比较是否相等来判断文件是否合并成功。

        //块文件目录
        File chunkFolder  = new File("D:\develop\chunk_target");
        //原始文件
        File originalFile  = new File("D:\develop\chunk\001-ChatGPT背景介绍.mp4");
        //合并文件
        File mergeFile  = new File("D:\develop\chunk\1.mp4");
        if (mergeFile.exists()) {
            mergeFile.delete();
        }
        //创建新的合并文件
        mergeFile.createNewFile();
        //用于写文件
        RandomAccessFile raf_write = new RandomAccessFile(mergeFile, "rw");
        //指针指向文件顶端
        raf_write.seek(0);
        //缓冲区
        byte[] bytes = new byte[1024];
        //分块列表
        File[] files = chunkFolder.listFiles();
        // 转成集合,便于排序
        List<File> fileList = Arrays.asList(files);
        // 从小到大排序
        Collections.sort(fileList, (o1, o2) -> Integer.parseInt(o1.getName()) - Integer.parseInt(o2.getName()));
        // 合并文件
        for (File chunkFile  : fileList) {
            Integer len = -1;
            RandomAccessFile raf_read = new RandomAccessFile(chunkFile , "r");
            while ((len = raf_read.read(bytes)) != -1){
                raf_write.write(bytes,0,len);
            }
            raf_read.close();
        }
        raf_write.close();

        //校验文件
        try(FileInputStream fileInputStream = new FileInputStream(originalFile);
            FileInputStream mergeFileStream = new FileInputStream(mergeFile)) {
            //取出原始文件的md5
            String originalMd5  = DigestUtils.md5Hex(fileInputStream);
            //取出合并文件的md5进行比较
            String mergeFileMd5 = DigestUtils.md5Hex(mergeFileStream);
            if(originalMd5.equals(mergeFileMd5)){
                System.out.println("合并文件成功");
            }else {
                System.out.println("合并文件失败");
            }
        }
    }
}