基本思路:
文件分割:将一个文件分割成若干个独立的文件。
设置分割后小文件文件的字节数,然后读取被分割文件,
将对应的字节数写入分割后的小文件中。
使用seek定位下一次读取位置。
文件合并:将分割后的若干的文件合并成一个完整的文件。
按照原有分割顺序逐个读取分割后的小文件,
然后以追加的方式写入合并的文件中。
读取被分割文件将指定字节数写入分割后小文件时,下一次读取时要确保当前读取位置是上一次的写入的终点。
例如文件有5000K,设置分割后的文件大小1000K,那么第一次从0开始读取1000K写入小文件1,第二次就要从1000开始读取1000K写入小文件2.
这时就需要用到seek()不断设置文件读取位置。
seek是RandomAccessFile类中的函数
构造方法,mode为设置读写方法,“”r“为只读”w”为只写。
设置文件指针偏移量,下一次读或写时,从当前设置的位置开始。
read,write方法与输入输出流函数相同。
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.OutputStream; import java.io.RandomAccessFile; import java.util.ArrayList; import java.util.List; public class FileSplit { private String filePath;//文件路径 private long blockSize;//每一块大小 private int blockNum;//块个个数 private List<String> blockName;//每一块名称 private String [] name; public FileSplit(){ this.blockName = new ArrayList<String>(); } public FileSplit(String filePath){ this(filePath,1024);//未知的尺寸则默认1024 } public FileSplit(String filePath, long blockSize){ this(); this.filePath = filePath; this.blockSize = blockSize; init(); } public String getFilePath() { return filePath; } public void setFilePath(String filePath) { this.filePath = filePath; } public long getBlockSize() { return blockSize; } public void setBlockSize(long blockSize) { this.blockSize = blockSize; } public int getBlockNum() { return blockNum; } public void setBlockNum(int blockNum) { this.blockNum = blockNum; } public List<String> getBlockName() { return blockName; } public void setBlockName(List<String> blockName) { this.blockName = blockName; } private void initBlockName(String destPath){ name = new File(filePath).getName().split("\."); for(int i = 0; i < blockNum; i++){ blockName.add(i,destPath + "\" + name[0] + "_" + i + "." +name[1]); } } public void init(){ File src = new File(filePath); //路径名不存在,或该路径表示的文件不存,或是文件夹在则结束。 if(filePath == null || !src.exists()||src.isDirectory()){ return; } if(blockSize >= src.length()) this.blockSize = src.length(); this.blockNum = (int)Math.ceil(src.length()*1.0/blockSize); } //destPath分割文件存放目录 public void split(String destPath){//分割函数 initBlockName(destPath);//初始化分割后的文件名 long start = 0; for(int i = 0; i < blockNum; i++){ if(i == blockNum - 1)//计算最后一块大小 blockSize = new File(filePath).length()%blockSize; split_m(i,start,blockSize);//参数含义:第i块,读取位置,读取内容大小 start += blockSize;//更新起始位置 // System.out.println(start); } } //开始分割,每次分割一块 private void split_m(int blockNum,long start,long blockSize){ int len = 0; byte[] flush = new byte[1024]; RandomAccessFile raf = null;//源文件 BufferedOutputStream bos = null;//分割后文件 try { bos = new BufferedOutputStream(new FileOutputStream(new File(blockName.get(blockNum)))); raf = new RandomAccessFile(new File(filePath),"r"); try { raf.seek(start);//确定读取位置 while(-1 != (len = raf.read(flush))){//当前块分割完成或文件已读取完跳出循环。 //System.out.printf("%d %d %d %s ",start,blockSize,len,blockName.get(blockNum)); if((blockSize - len) >=0){//当前块大小-写入字节数,判断剩余字节 bos.write(flush,0,len);//如果块剩余大小大于读取字节数,则写入读取字节数 blockSize -= len; }else{//如果小于,则写入当前块剩余字节数 bos.write(flush, 0, (int)blockSize); break;//分块文件已写满,跳出当前循环 } } bos.flush(); bos.close(); raf.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public void Merge(String mergePath){//合并文件夹路径 int len; byte[] flush = new byte[1024]; InputStream is = null; OutputStream bos = null; for(int i = 0; i < blockNum; i++){ try { //每次将一个分割后的文件写入合并文件中。 //写入方法为追加 bos = new BufferedOutputStream(new FileOutputStream(new File(mergePath,"merge." + name[1]),true)); is = new BufferedInputStream(new FileInputStream(new File(blockName.get(i)))); while(-1 != (len = is.read(flush))){//直到被分割的单个小文件读取完 is.read(flush);//将读取内容放入flush bos.write(flush,0,len);//将读取内容写入文件。 } bos.flush(); bos.close(); is.close();//释放当前资源,下次读取下一个小文件。 } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
public class Main { public static void main(String[] args){ FileSplit f = new FileSplit("F:\依风\Desktop\temp.txt",500);//被分割文件,分割后的字节数 f.split("F:\依风\Desktop");//分割后小文件的存放位置 f.Merge("F:\依风\Desktop");//合并后大文件的存放位置 } }