文件的分割与合并(Java实现)

文件的分割与合并(Java)

一、文件分割实现思想

     1、设置分割文件(块)的大小;
    2、通过输入流获取源文件的大小;
    3、根据1、2步的计算结果计算出分割后的文件个数(源文件的大小 / 设置分割文件的大小 ,如果设置的文件大小大于源文件的大小,接下来判断1、2步计算结果,如果余数为0,则文件个数为商值,如果余数大于0,则文件个数为商值加1。
如果设置分割文件的大小小于源文件的大小,那么文件个数为1。);
    4、分割文件(边读边写)。

二、文件合并实现思想

1、文件合并与文件分割实现思想的第4步类似,就是边读边写。


方式一:调用API中的RandomAccessFile,此类的实例支持对随机存取文件的读取和写入。按块分割与合并,示例代码如下:

package com.cn.filesplite1;
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;

public class SplitFile {
	//文件的路径
	private String filePath;
	//文件名
	private String fileName;
	//文件大小
	private long length;
	//块数
	private int size;
	//每块的大小
	private long blockSize;
	//分割后的存放目录
	private String destBlockPath;
	//每块的名称
	private List<String> blockPath;
	
	public SplitFile(){
		blockPath = new ArrayList<String>();
	}
	public SplitFile(String filePath,String destBlockPath){
		this(filePath,destBlockPath,1024);		
	}
	public SplitFile(String filePath,String destBlockPath,long blockSize){
		this();
		this.filePath= filePath;
		this.destBlockPath =destBlockPath;
		this.blockSize=blockSize;
		init();
	}
	
	/**
	 * 初始化操作 计算 块数、确定文件名
	 */
	public void init(){
		File src =null;
		//健壮性
		if(null==filePath ||!(((src=new File(filePath)).exists()))){
			return;
		}
		if(src.isDirectory()){
			return ;
		}
		//文件名
		this.fileName =src.getName();
		
		//计算块数 实际大小 与每块大小
		this.length = src.length();
		//修正 每块大小
		if(this.blockSize>length){
			this.blockSize =length;
		}
		//确定块数		
		size= (int)(Math.ceil(length*1.0/this.blockSize));
		//确定文件的路径
		initPathName();
	}
	
	private void initPathName(){
		for(int i=0;i<size;i++){
			this.blockPath.add(destBlockPath+"/"+this.fileName+".part"+i);
		}
	}
	
	/**
	 * 文件的分割
	 * 0)、第几块
	 * 1、起始位置
	 * 2、实际大小
	 * @param destPath 分割文件存放目录
	 */
	public void split(){	
		long beginPos =0;  //起始点
		long actualBlockSize =blockSize; //实际大小		
		//计算所有块的大小、位置、索引
		for(int i=0;i<size;i++){
			if(i==size-1){ //最后一块
				actualBlockSize =this.length-beginPos;
			}			
			spiltDetail(i,beginPos,actualBlockSize);
			beginPos+=actualBlockSize; //本次的终点,下一次的起点
		}
		
	}
	/**
	 * 文件的分割 输入 输出
	 * 文件拷贝
	 * @param idx 第几块
	 * @param beginPos 起始点
	 * @param actualBlockSize 实际大小
	 */
	private void spiltDetail(int idx,long beginPos,long actualBlockSize){
		//1、创建源
		File src = new File(this.filePath);  //源文件
		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));
			//读取文件
			raf.seek(beginPos);
			//缓冲区
			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;
				}
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			FileUtil.close(bos,raf);
		}
	}
	/**
	 * 文件的合并
	 */
	public void merge(String destPath){
		//创建源
		File dest =new File(destPath);
		//选择流
		BufferedOutputStream bos=null; //输出流
		SequenceInputStream sis =null ;//输入流
		//创建一个容器
		Vector<InputStream> vi = new Vector<InputStream>();		
		try {
			for (int i = 0; i < this.blockPath.size(); i++) {
				vi.add(new BufferedInputStream(new FileInputStream(new File(this.blockPath.get(i)))));
			}	
			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))){						
				bos.write(flush, 0, len);
			}
			bos.flush();
			FileUtil.close(sis);
		} catch (Exception e) {
		}finally{
			FileUtil.close(bos);
		}		
	}
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		//1024 * 30 表示按照每块30Kb大小分割
		SplitFile split = new SplitFile("F:/123/1234/logFile.txt","F:/123/",1024 * 30);
		
		System.out.println(split.size);
		
//		split.split();
		
		split.merge("F:/123/logFile.txt");
		
	}

}
package com.cn.filesplite1;
import java.io.Closeable;
public class FileUtil {
	/**
	 * 工具类关闭流
	 * 可变参数: ...  只能形参最后一个位置,处理方式与数组一致
	 */
	public static void close(Closeable ... io){
		for(Closeable temp:io){
			try {
				if (null != temp) {
					temp.close();
				}
			} catch (Exception e) {
			}
		}
		
	}
	/**
	 * 使用泛型方法
	 */
	public static <T extends Closeable> void closeAll(T ... io){
		for(Closeable temp:io){
			try {
				if (null != temp) {
					temp.close();
				}
			} catch (Exception e) {
			}
		}
	}

}

方式二:用读写的方式实现文件的分割与合并,具体实现如下代码所示:

定义一个抽象类

package com.cn.filesplite2;
import java.io.File;
import java.io.IOException;
/**
 * 文件分割
 * @author Administrator
 *
 */
public abstract class SplitFile {
	/**
	 * 设置单个文件的大小
	 * 根据自己需求设置大小,字节进率为1024,本例中设置的最大分割文件大小是2Gb。
	 */
	public static long MAX_BYTE = 1024 * 1024 * 1024 * 2L;  //2G
	
	/**
	 * 获取可以分割的文件数
	 * @param fileByte 文件大小
	 * @param fileParh 文件路径
	 * @return
	 */
	public abstract int getSplitFileNum(long fileByte,String fileParh);
	/**
	 * 获取文件长度
	 * @param file
	 * @return
	 * @throws IOException
	 */
	public abstract long getFileLength(File file) ;
	/**
	 * 分割文件
	 * @param srcFile
	 * @param splitFileNum
	 * @return
	 * @throws IOException
	 */
	public abstract String[] splitFile (File srcFile,int splitFileNum) throws IOException;
	/**
	 * 合并文件
	 * @param files
	 * @param newFile
	 * @throws IOException
	 */
	public abstract void mergeFile(String[] files,String newFile) throws IOException;
	
}
实现类

package com.cn.filesplite2;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
/**
 * 文本文件分割
 * @author Administrator
 *
 */
public class SplitTextFile extends SplitFile{
	
	@Override
	public long getFileLength(File file) {
		FileReader fr =  null;
		BufferedReader br = null;
		//文件大小
		long fileSize = 0;
		try {
			fr = new FileReader(file);
			br = new BufferedReader(fr);
			String line = br.readLine();
			//按行读取文件
			while(line != null){
				//计算文件大小
				fileSize += line.length();
				line = br.readLine();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			//关闭输入流
			try {
				if(br != null){
					br.close();
				}
				if(fr != null){
					fr.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		//返回文件大小
		return fileSize;
	}
	
	@Override
	public int getSplitFileNum(long fileByte,String fileParh){
		fileByte = getFileLength(new File(fileParh));
		if(MAX_BYTE < fileByte){
			if(fileByte % MAX_BYTE == 0){
				return (int) (fileByte/MAX_BYTE);
			}else{
				return (int) (fileByte/MAX_BYTE) + 1;
			}
		}
		return 1;
	}

	@Override
	public String[] splitFile(File srcFile, int splitFileNum) throws IOException {
		splitFileNum = getSplitFileNum(getFileLength(srcFile), srcFile.toString());
		if(splitFileNum <= 0){
			return null;
		}
		FileReader fr = null;
		BufferedReader br = null;
		long readNum = 0;
		String[] splits = new String[splitFileNum];
		try {
			fr = new FileReader(srcFile);
			br = new BufferedReader(fr);
			int i = 0;
			while(splitFileNum > i){
				//分割后的文件名
				String name = null;
				//文件后缀
				String nameLast = null;
				if(srcFile.getName().indexOf(".") != -1){
					name = srcFile.getName().substring(0, srcFile.getName().indexOf("."));
					int last = srcFile.getName().lastIndexOf(".");
//					System.out.println(i);
//					String string = str.substring(i);
					nameLast = srcFile.getName().substring(last);
					
				}else{
					name = srcFile.getName();
				}
				splits[i] = srcFile.getParent() + "/" + name + "_" + i + nameLast;
				File wfile = new File(splits[i]);
				if(!wfile.exists()){
					wfile.getParentFile().mkdirs();
					wfile.createNewFile();
				}
				FileWriter fw = new FileWriter(wfile,false);
				BufferedWriter bw = new BufferedWriter(fw);
				String line = br.readLine();
				int flush = 0;
				while(line != null){
					if(line.trim().length() == 0){
						line = br.readLine();
						continue;
					}
					readNum += line.length();
					if(i + 1 == splitFileNum){
						bw.write(line);
						bw.newLine();
					}else{
						if(readNum >= MAX_BYTE){
							bw.write(line);
							bw.newLine();
							break;
						}else{
							bw.write(line);
							bw.newLine();
						}
					}
					line = br.readLine();
					if(flush % 100 == 0){
						bw.flush();
					}
				}
				bw.flush();
				fw.flush();
				bw.close();
				fw.close();
				readNum = 0;
				i++;
			}
		} catch (RuntimeException e) {
			e.printStackTrace();
		}
		finally{
			try {
				if(br != null) br.close();
				if(fr != null) fr.close();
			} catch (Exception e) {
				e.printStackTrace();
			}finally{
				br = null;
				fr = null;
			}
		}
		return splits;
	}

	@Override
	public void mergeFile(String[] files, String newFile) throws IOException {
		File wfile = new File(newFile);
		FileWriter writer = null;
		BufferedWriter bufferedWriter = null;
		try {
			writer = new FileWriter(wfile,false);
			bufferedWriter = new BufferedWriter(writer);
			for(int i = 0; i < files.length; i++){
				File rFile = new File(files[i]);
				FileReader reader =  new FileReader(rFile);
				BufferedReader bufferedReader = new BufferedReader(reader);
				String line = bufferedReader.readLine();
				while(line != null){
					if(line.trim().length() == 0){
						line = bufferedReader.readLine();
						continue;
					}
					bufferedWriter.write(line);
					bufferedWriter.newLine();
					line = bufferedReader.readLine();
				}
			}
			bufferedWriter.flush();
			writer.flush();
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			if(bufferedWriter != null)
				bufferedWriter.close();
			bufferedWriter = null;
			if(writer != null)
				writer.close();
			writer = null;
		}
	}
}
测试类

package com.cn.filesplite2;

import java.io.File;
import java.io.IOException;
import org.junit.Test;

public class TestSplitFile {
	SplitTextFile splitTextFile = new SplitTextFile();
	@Test
	public void funSplitFile() throws IOException{
		String srcPath = "E:/splitfile/splitfile.txt"; 
		File file = new File(srcPath);
		long fileLength = splitTextFile.getFileLength(file);
		System.out.println("文件大小:" + fileLength);
		int partitionFileNum = splitTextFile.getSplitFileNum(fileLength, srcPath);
		System.out.println("个数" + partitionFileNum);
		//文件分割
		splitTextFile.splitFile(new File(srcPath), partitionFileNum);
	}
	
	@Test
	public void funMergeFile() throws IOException{
		
		String[] files = {"E:/splitfile/splitfile0",
						"E:/splitfile/splitfile1",
						"E:/splitfile/splitfile2"
//						...files/
						};
		String newFile = "E:/splitfile/newmergefile";
		splitTextFile.mergeFile(files, newFile);
		
	}
}

以上内容如有任何问题或错误,恳请大家能给予意见,我会及时更正,谢谢大家。





  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值