一、文件分割示意图

文件分割与合并(Java)_Java

二、文件合并示意图

方式一:通过文件追加的方式
文件分割与合并(Java)_Java_02

方式二:通过SequenceInputStream对其他输入流的逻辑串联。
文件分割与合并(Java)_Java_03

测试RandomAccessFile随机访问文件

package FileSplitMerge;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;

import IOOthers.FileUtil;

/**
 * RandomAccessFile
 * 此类的实例支持对随机访问文件的读取和写入。
 * 
 * 文件分割的思路
 * 1、 分割的块数 size   n块
 * 2、 每一块的大小 blocksize
 *    最后一块:总的文件大小-(n-1)*blockSize
 */

public class Demo01 {
    public static void main(String[] args) throws IOException {
        RandomAccessFile rnd = new RandomAccessFile(new File("G:/writer.txt"), "r");
        //UTF-8-->英文使用1个字节,中文使用3个字节来编码
        //GBK-->每个字符占用2个字节
        //从第12个读起       这是采用的是UTF-8  
        rnd.seek(12);
        //定义缓冲大小
        byte[] flush = new byte[1024];
        //接收长度
        int len=0;

        while(-1!=(len=rnd.read(flush)))
        {
            if(len>=48)
            {
                System.out.println(new String(flush,0,48));
            }   
            else {
                System.out.println(new String(flush,0,len));
            }
        }
        FileUtil.close(rnd);
    }
}

运行结果:

都有青春,
每个青春都有一个故事�
re ESX资源管理与性能优化
S1.1.11VMware
��FT-Practise
实验演示7:vApp-Practise

文件的分割与合并

package FileSplitMerge;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.io.SequenceInputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

import IOOthers.FileUtil;

@SuppressWarnings("all")
public class SplitFile {

    //文件的路径
    private String filePath;
    //块数
    private int size;
    //每块的大小
    private long blocksize;
    //文件名
    private String fileName;
    //文件大小
    private long length;
    //分割后的存放目录
    private String destBlockPath;
    //每块的名称
    private List<String> blockPath;


    public SplitFile() {
        blockPath = new ArrayList<String>() ;
    }   
    public SplitFile(String filePath,String destBlockPath) {
        this(filePath,1024, destBlockPath);
    }

    public SplitFile(String filePath, long blocksize,String destBlockPath) {
        this();
        this.filePath = filePath;
        this.destBlockPath = destBlockPath;
        this.blocksize = blocksize;
    }


    /**
     * 初始化操作 计算块数、确定文件名
     */
    public void init()
    {
        File src = null;
        //健壮性    创建成功就会得到构造方法初始化的值
        if(null==filePath || !(src=new File(filePath)).exists())
        {
            return;
        }
        if(src.isDirectory())
        {
            return;
        }

        //文件名    g:/writer.txt的 writer.txt
        this.fileName = src.getName(); 
        //文件的大小
        this.length = src.length();

        //修正    每块的大小
        if(this.blocksize>length) //如果每块的大小大于文本的长度,则每块的大小=长度
        {
            this.blocksize = length;
        }

        //确定块数        ceil最小(最接近负无穷大)浮点值,该值大于等于该参数,并等于某个整数。
        size = (int) Math.ceil(length*1.0/this.blocksize);

        //确定文件的路径
        initPathName();
    }

    private void initPathName()
    {
        for(int i=0;i<size;i++)
        {
            //List容器里面增加每一块的路径
            this.blockPath.add(destBlockPath+"/"+this.fileName+".part"+i);
        }
    }

    /**
     * 文件分割
     * 确定在第几块
     * 1、起始位置
     * 2、实际大小
     * @param destPath 分割文件存放目录
     * @throws IOException 
     */
    public void split(String destPath) throws IOException
    {
        //确定文件的路径
        //每一块的名称
        //initPathName(destPath);
        long beginPos = 0;//起始点
        long actualBlockSize = blocksize;//实际大小
        //计算所有快的大小、位置、索引
        for(int i=0;i<size; i++)
        {
            if(i == size-1)
            {
                //最后一块
                actualBlockSize = this.length-beginPos;
            }
            //具体分割方法     第几块    起始分割地址        实际的块大小
            splitDetail(i,beginPos,actualBlockSize);
            beginPos += actualBlockSize;//本次的终点,下一次的起点
        }
    }

    /**
     * 文件分割  输入 输出
     * 文件拷贝
     * @param idx 第几块
     * @param beginPos 起始点
     * @param actualBlockSize 实际大小
     * @throws IOException 
     */
    public void splitDetail(int idx,long beginPos,long actualBlockSize) throws IOException
    {
        //1、创建源
        File src = new File(this.filePath);//源文件
        //得到第几块的路径       List容器取出块路径
        File dest = new File(this.blockPath.get(idx));//目标文件

        //2、选择流
        RandomAccessFile raf = null;//输入流
        BufferedOutputStream bos = null;//输出流
        try 
        {
             raf = new RandomAccessFile(src, "r");
             bos = new BufferedOutputStream(new FileOutputStream(dest));
             //3、读取文件
             raf.seek(beginPos);
             //4、缓冲区
             byte[] flush = new byte[1024];
             int len = 0;
             while(-1!=(len=raf.read(flush)))
             {
                 //写出
                 if(actualBlockSize-len>=0)//判断是否足够
                 {
                     bos.write(flush,0,len);//写出
                     actualBlockSize -= len;//剩余量                
                 }
                 else   
                 {
                     //读取每一块实际大小的最后一小部分   最后一次写出
                     bos.write(flush,0,(int)actualBlockSize);
                     break;//每个block最后一部分读取完之后,一定要break,否则就会继续读取
                 }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        finally{
            FileUtil.close(bos,raf);
        }
    }

    /**
     * 文件的合并   (方法一)
     */
    public void merge1(String destPath)
    {
        //创建源
        File dest = new File(destPath);
        //选择流
        BufferedOutputStream bos = null;//输出流
        BufferedInputStream bis = null;//输入流
        try {
            bos = new BufferedOutputStream(new FileOutputStream(dest,true));//表示追加

            for(int i=0; i<this.blockPath.size();i++)
            {
                //读取
                bis = new BufferedInputStream(new FileInputStream
                        (new File(this.blockPath.get(i))));
                //缓冲区
                byte[] flush = new byte[1024];
                //接收长度
                int len = 0;
                while(-1 !=(len = bis.read(flush)))
                {
                    //打印到控制台
                    //System.out.println(new String(flush,0,len));
                    bos.write(flush,0,len);                 
                }
                bos.flush();
                FileUtil.close(bis);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        finally
        {
            FileUtil.close(bos);
        }   
    }

    /**
     * 文件的合并  (方法二)
     */ 
    public void merge(String destPath) throws IOException
    {
        //1、创建源
        File dest = new File(destPath);

        //2、选择流
        //SequenceInputStream 表示其他输入流的逻辑串联。它从输入流的有序集合开始,
        //并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,
        //直到到达包含的最后一个输入流的文件末尾为止。 

        SequenceInputStream sis = null;//输入流
        BufferedOutputStream bos = null;//输出源   

        //创建一个容器
        Vector<InputStream> vi = new Vector<InputStream>();
        for(int i=0; i<this.blockPath.size();i++)
        {
            vi.add(new BufferedInputStream(
                    new FileInputStream(new File(this.blockPath.get(i)))));     
        }
        //SequenceInputStream sis = new SequenceInputStream(vi.elements()); 
        bos = new BufferedOutputStream(new FileOutputStream(dest,true));//表示追加
        sis = new SequenceInputStream(vi.elements());

        //缓冲区
        byte[] flush = new byte[1024];
        //接收长度
        int len = 0;
        while(-1 !=(len = sis.read(flush)))
        {
            //打印到控制台
            //System.out.println(new String(flush,0,len));
            bos.write(flush,0,len);     
        }
        bos.flush();
        FileUtil.close(sis);
    }

    public static void main(String[] args) {
        //源文件路径、每块的大小(字节数)、目标快的路径
        SplitFile split = new SplitFile("g:/writer.txt",100,"g:/try");

        //文件初始化
        split.init();

        //文件分割
        try {
            //split.split("g:/try");
            split.split(split.destBlockPath);   
        } catch (IOException e) {
            e.printStackTrace();
        }

        //文件合并
        try {
            split.merge("g:/try/test.txt");
        } catch (IOException e) {
            e.printStackTrace();
        }
        //System.out.println(file.size);
    }
}