java实现大文件的拆分与合并

文章目录

  • 前言
  • 一、废话少说,直接上代码
  • 二.测试用例
  • 总结


前言

我需要把一个大文件上传到网盘上,由于网盘禁止上传大于4G的文件,所以我想通过Java程序来把大文件分割为小文件后,再上传,等需要的时候,通过程序把文件进行合并即可。

一、废话少说,直接上代码

代码如下:

package com.xm.file;

import java.io.*;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 1.把大文件按照指定大小分割成多个小文件
 * 2.把多个小文件分割为大文件
 * 测试用例@com.xm.FileSplitAndCombineTest
 */
public class FileSplitAndCombine {

    private static int THOUSAND_TWENTY_FOUR= 1024; // one thousand and twenty-four



    /**
     * 把大文件拆分为多个小文件
     *
     * @param sourcePath 需要被拆分的文件路径
     * @param desPath    拆分后的文件应该存放的文件路径
     * @param newName    每一个小文件名
     */
    public static void splitFile(String sourcePath, String desPath, String newName) {

        try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File(sourcePath)))) {
            for (int i = 0; ; i++) {
                String filePath = desPath + File.separatorChar +newName+"_" +i;
                if (singleSplitFile(bis, filePath, THOUSAND_TWENTY_FOUR)) break;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    /**
     * @param bis 输入流
     * @param filePath       新文件存储的文件夹路径
     * @param partitionSize 每个文件的大小 单位MB
     * @throws IOException
     */
    private static boolean singleSplitFile(BufferedInputStream bis, String filePath,int partitionSize) throws IOException {
        int length = partitionSize * THOUSAND_TWENTY_FOUR * THOUSAND_TWENTY_FOUR;
        byte[] buffer = new byte[THOUSAND_TWENTY_FOUR];
        int tempLength;

        System.out.println(nowTime() + "----->>>> begin split " + filePath);
        try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File(filePath)))) {
            while ((tempLength = bis.read(buffer)) != -1) {
                bos.write(buffer, 0, tempLength);
                if ((length = length - tempLength) <= 0) break;
            }
        }
        System.out.println(nowTime() + "<<<<----- yet finish split" + filePath);

        return tempLength < 0;
    }

    /**
     * 把指定文件夹内的文件合并为一个文件
     *
     * @param sourcePath 需要被合并的文件所在的文件中路径
     * @param desPath    合并后的文件存放位置
     */
    public static void combineFile(String sourcePath, String desPath) {

        List<String> sortedFileNames = sortFilesName(sourcePath);
        if (sortedFileNames == null) {
            System.out.println(sourcePath+"路径下不存在文件夹");
            return;
        }

        try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File(desPath)))) {
            for (String sortedFileName : sortedFileNames) {
                copyFile(bos, sourcePath + File.separatorChar + sortedFileName);
            }
            System.out.println("all finish...");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 把目标文件合并到输出流中
     *
     * @param bos 缓冲输出流
     * @param des 目标文件路径
     * @throws IOException
     */
    private static void copyFile(BufferedOutputStream bos, String des) throws IOException {

        try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File(des)))) {
            System.out.println(nowTime()+ "------>>>>"+des + "开始合并");
            byte[] bytes = new byte[1024];
            int length;
            while ((length = bis.read(bytes)) != -1) {
                bos.write(bytes, 0, length);
            }
            System.out.println(nowTime()+ "<<<<------"+des + "合并完成");
        }
    }

    /**
     * 对指定文件夹内的文件名进行排序 (增序)
     *
     * @param fileDir
     * @return
     */
     private static List<String> sortFilesName(String fileDir) {
        File file = new File(fileDir);
        File[] files = file.listFiles();
        if (null == files || files.length == 0) {
            return null;
        }
        Pattern compile = Pattern.compile("^.+_\\d+$");
        return Arrays.stream(files).filter(file1 -> {
            if (file1.isDirectory()){
                System.out.println("waring: "+ file1.getName() +"不是一个文件");
                return false;
            }
            String file1Name = file1.getName();
            Matcher matcher = compile.matcher(file1Name);
            if (!matcher.find()){
                System.out.println("waring:文件名 "+file1Name+"不符合 文件名_数字的命名规范");
                return false;
            }
            return true;
        }).map(File::getName)
                .sorted((fileName1,fileName2)->{
                    String[] split1 = fileName1.split("_");
                    String[] split2 = fileName2.split("_");
                    return Integer.parseInt(split1[split1.length - 1])-Integer.parseInt(split2[split2.length - 1]);
                }).collect(Collectors.toList());
    }
    
    private static String nowTime(){
       return new Date().toLocaleString();
    }
}

二.测试用例

代码如下:

package com.xm;

import com.xm.file.FileSplitAndCombine;


public class FileSplitAndCombineTest {
    public static void main(String[] args) {
       //文件分割
        splitTest();
        //文件合并
        combineTest();
    }

    private static void splitTest() {
        String sourcePath = "E:\\fileSplitTest\\source.zip";
        String desPath = "E:\\fileSplitTest";
        String newName = "split";

        FileSplitAndCombine.splitFile(sourcePath, desPath, newName);
    }

    private static void combineTest() {
        String desPath  = "E:\\fileSplitTest\\combine.zip";
        String sourcePath = "E:\\fileSplitTest";

        FileSplitAndCombine.combineFile(sourcePath, desPath);
    }
}


总结

代码比较简单,希望能够帮助到有需要的人,另外文件合并后建议大家通过MD5计算工具查看源文件与恢复后的文件MD5值是否一致(对于一些文本文件存在即使md5值不一样也能打开的情况,实质上文件已经损坏)如果您有任何疑问都可以通过评论联系我。

你可能感兴趣的:(java)