Java 文件的分割与合并完整代码

package com.maple.file;


import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Arrays;
import java.util.regex.Pattern;

/**
 * 文件的分割与合并 注意要遵循类的设计原则 方法与方法之间耦合度要低 考虑设计模式
 * 
 * @author RhymeChiang
 * @date 2017/10/21
 */
public class FileSpliteAndMerge {

    private final int BLOCK_SIZE = 5;
    private final String DEST_PATH = "c:/user/splitFileDir";
    private final String SUFFIX = "split-part-";
    private final String FILE_NAME_MASK = "_";
    private String fileName;
    /**
     * 源文件
     */
    private String srcPath;

    /**
     * 分割文件的保存目录
     */
    private String destPath;

    /**
     * 文件分割块的大小
     */
    private long blockSize;
    /**
     * 文件的分割块数
     */
    private int blocksNumber;

    /**
     * 无参构造方法 初始化分割块的大小 初始化分割文件的默认保存位置
     */
    public FileSpliteAndMerge() {
        super();
        this.blockSize = BLOCK_SIZE;
        this.destPath = DEST_PATH;
    }

    /**
     * 分割文件构造方法
     * 
     * @param blockSize
     *            文件分割块的大小
     * @param srcPath
     *            文件分割源文件
     * @param destPath
     *            分割文件保存位置
     */
    public FileSpliteAndMerge(long blockSize, String srcPath, String destPath) {
        super();
        this.blockSize = blockSize;
        this.srcPath = srcPath;
        this.destPath = destPath;
    }

    /**
     * 文件分割总方法重载方法
     */
    public void splitFile() {
        if (null == srcPath || srcPath.equals("")) {
            System.out.println("请使用setSrcPath(String)设置源文件路径");
        }
        splitFile(srcPath, blockSize, destPath);
    }

    /**
     * 文件分割总方法
     * 
     * @param srcPath
     *            源文件路径
     * @param blockSize
     *            分割块的大小
     */
    public void splitFile(String srcPath, long blockSize, String destPath) {

        File src = new File(srcPath);

        // 文件位置保存不合法则直接返回
        if (!checkSaveDir(destPath)) {
            return;
        }

        // 文件不合法直接退出
        if (!checkFile(src)) {
            System.out.println("文件不存在或不合法,请确保文件路径正确且该文件不是目录");
            return;
        }
        try {
            splitFileDetail(src, blockSize, destPath);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 合并splitFilesDir目录下的分割文件
     * 
     * @param splitFilesDir
     * @param destPath
     */
    public void mergeSplitFiles(String splitFilesDir, String destPath) {

        File splitDir = new File(splitFilesDir);
        if(!checkSplitFileDir(splitDir)) {
            return;
        }
        try {
            mergeSplitFilesDetails(splitDir, destPath);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
    /**
     * 合并分割文件具体操作
     * 
     * @param splitDir
     *            分割文件所在目录
     * @param destPath
     *            合并文件保存位置
     * @throws IOException 
     */
    private void mergeSplitFilesDetails(File splitDir, String destPath) throws IOException {
        File[] listFiles = splitDir.listFiles();
        fileName = getSplitFileName(listFiles[0]);
        int filesNum = listFiles.length;
        //合并文件目录保存位置不合法
        if(!checkMergeDestPath(fileName,destPath)) {
            return;
        }

        /**
         * 写到指定文件并追加
         */
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File(destPath,fileName)));

        for (int i = 1; i <= filesNum; i++) {
            for(File f:listFiles) {
                if(f.getName().contains(i+"")) {
                    bos.write(readFile(f));
                    bos.flush();
                    break;
                }
            }
        }
        bos.flush();
        closeAll(bos);
    }

    /**
     * 检车合并文件目录保存的合法性
     * @param mergeFileName
     * @param destPath
     * @return
     */
    public boolean checkMergeDestPath(String mergeFileName,String destPath) {
        File dest = new File(destPath);
        if(!dest.exists()) {
            System.out.println("合并文件保存地址不存在");
            return false;
        }

        if(!dest.isDirectory()) {
            System.out.println("合并文件保存地址不是一个目录");
            return false;
        }

        for(File f:dest.listFiles()) {
            if(f.getName().equals(mergeFileName)) {
                System.out.println("合并保存地址中存在和保存文件同名的文件");
                return false;
            }
        }

        return true;
    }

    /**
     * 将文件中内容读入字节数组中
     * @param f
     * @return
     * @throws IOException
     */
    private byte[] readFile(File f) throws IOException {
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(f));
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        int len = 0;
        byte [] buffer = new byte[1024];
        while(-1!=(len=bis.read(buffer))) {
            baos.write(buffer,0,(int)f.length());
        }
        byte[] byteArray = baos.toByteArray();
        closeAll(baos,bis);
        return byteArray;
    }

    /**
     * 获取分割文件原名
     * 
     * @param f
     * @return
     */
    public String getSplitFileName(File f) {
        String name = f.getName();
        return name.substring(name.indexOf(FILE_NAME_MASK)+1);
    }

    /**
     * 检查分割文件目录以及其中的目录是否合法
     * 
     * @param splitDir
     * @return
     */
    private boolean checkSplitFileDir(File splitDir) {
        if (!splitDir.exists()) {
            System.out.println("分割文件指定目录不存在");
            return false;
        }

        if (!splitDir.isDirectory()) {
            System.out.println("分割文件指定目录不是一个目录");
            return false;
        }

        String fileName = getSplitFileName(splitDir.listFiles()[0]);
        String reg = SUFFIX + "\\d*"+"_"+fileName;
        for (File f : splitDir.listFiles()) {
            if (!f.getName().matches(reg)) {
                System.out.println("目录中包含非法分割文件");
                return false;
            }
        }
        return true;
    }

    /**
     * 检查是否为一个合法的文件
     * 
     * @param src
     *            源文件地址
     * @return
     */
    private boolean checkFile(File src) {
        // 如果文件不存在或文件为目录则返回false
        if (!src.exists() || src.isDirectory()) {
            return false;
        }
        // 文件合法返回true
        return true;
    }

    /**
     * 文件分割具体操作
     * 
     * @param src
     *            源文件
     * @param blockSize
     *            分割快的大小,单位为字节
     * @throws IOException
     */
    private void splitFileDetail(File src, long blockSize, String destPath) throws IOException {
        // 如果分割块的大小大于总文件大小,则将其调整为文件的总大小
        if (blockSize > src.length()) {
            blockSize = src.length();
        }
        // 总的分割块的块数
        blocksNumber = (int) Math.ceil(src.length() * 1.0 / blockSize);
        /**
         * 进行文件的分割,使用以下的方法读取定长的文件字符 int read(byte[] b, int off, int len)
         * 创建RandomAccessFile对象并设置模式为r只读
         **/
        RandomAccessFile rf = new RandomAccessFile(src, "r");
        byte buffer[] = new byte[(int) blockSize];
        int len = -1;
        int count = 1;
        while (-1 != rf.read(buffer)) {
            saveByteToFile(src, count, buffer, destPath);
            count++;
        }
        closeAll(rf);
    }

    /**
     * 将分割文件进行保存
     * 
     * @param data
     * @param destPath
     * @throws FileNotFoundException
     */
    private void saveByteToFile(File src, int count, byte[] data, String destPath)
            throws FileNotFoundException, IOException {
        File dest = new File(destPath);
        FileOutputStream fos = null;
        BufferedOutputStream bos = null;

        dest = new File(dest, SUFFIX + count + FILE_NAME_MASK + src.getName());

        fos = new FileOutputStream(dest);
        bos = new BufferedOutputStream(fos);
        // 将分割数据写入到文件中
        bos.write(data, 0, data.length);
        bos.flush();
        // 关闭流
        closeAll(bos, fos);
    }

    /**
     * 确保分割文件保存目录的合法性 即确保文件保存位置存在且为一个空目录
     * 
     * @param dest
     * @return
     */
    private boolean checkSaveDir(String destPath) {
        File dest = new File(destPath);
        // 确保目标目录存在
        if (!dest.exists() || !dest.isDirectory()) {
            System.out.println("分割文件保存位置不存在或文件保存位置不是一个目录");
            return false;
        }

        // 确保保存目录为空目录,避免目录中有文件和分割文件发生同名冲突
        if (dest.listFiles().length != 0) {
            System.out.println("分割文件保存目录不是一个空目录,请选择一个空目录作为分割文件的保存位置");
            return false;
        }
        return true;
    }

    /**
     * 获取文件的后缀名
     * 
     * @param src
     * @return
     */
    public String getFileSuffix(File src) {
        String fileName = src.getName();
        int lastEnd = fileName.indexOf(".");
        return fileName.substring(lastEnd);
    }

    /**
     * 获取文件名
     * 
     * @param src
     * @return
     */
    public String getFileName(File src) {
        String fileName = src.getName();
        int lastEnd = fileName.indexOf(".");
        return fileName.substring(0, lastEnd);
    }

    /**
     * IO流关闭工具类
     * 
     * @param io
     */
    private <T extends Closeable> void closeAll(T... io) {
        for (T o : io) {
            if (null != o) {
                try {
                    o.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public String getSrcPath() {
        return srcPath;
    }

    public void setSrcPath(String srcPath) {
        this.srcPath = srcPath;
    }

    public long getBlockSize() {
        return blockSize;
    }

    public void setBlockSize(long blockSize) {
        this.blockSize = blockSize;
    }

    public String getDestPath() {
        return destPath;
    }

    public void setDestPath(String destPath) {
        this.destPath = destPath;
    }

    public static void main(String[] args) {
        FileSpliteAndMerge f = new FileSpliteAndMerge(5, "E://print.txt", "E://Test");
        f.splitFile();
        f.mergeSplitFiles("E://Test", "E://Test2");
    }

}