Java---IO---文件切割

实现对大文件的切割与合并。
按指定个数切(如把一个文件切成10份)或按指定大小切(如每份最小不小于1K),这两种方式都可以。

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.SequenceInputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;

import javax.swing.JFileChooser;
import javax.swing.JOptionPane;

import org.junit.Test;

/**
 * 2018年5月6日 上午10:30:14
 * @author <a href="mailto:[email protected]">宋进宇</a>
 *	演示文件切割和合并
 */
public class FileSplitAndMerge {
	//文件切割
	@Test
	public void split(){
		//创建文件选择窗口
		JFileChooser jfc = new JFileChooser();
		//显示出来
		int sel = jfc.showOpenDialog(null);
		if ( sel == JFileChooser.APPROVE_OPTION ) {
			//获取要被切割的文件
			File srcFile = jfc.getSelectedFile();
			//获取要存放的目标文件夹
			//这里直接在源文件的 文件夹下创建一个子文件。
			File targetDir = new File( srcFile.getParentFile(), "splitFiles" );
			try {
				//1:切割成指定大小
				splitFileBySize( srcFile, targetDir , 128*1024 );//128KB
				//2:切割成指定个数
				//splitFileByNum( srcFile, targetDir, 10 );
			} catch (IOException e) {
				JOptionPane.showMessageDialog(null, "切割失败!");
			}
		}
		
	}
	/**
	 * 切割成指定大小 的碎片文件
	 * @param srcFile 被切割的文件
	 * @param targetDir 目标文件夹
	 * @param size 指定大小(必须大于等于1KB)
	 * @throws IOException 出错异常
	 */
	private void splitFileBySize(File srcFile, File targetDir, long size ) throws IOException {
		//被切割的文件若不存在就返回
		if ( srcFile == null || !srcFile.exists() ) {
			return;
		}
		//判断存放的文件夹是否存在,如果不存在就创建
		if ( !targetDir.exists() ) {
			targetDir.mkdirs();
		}
		if ( size <1024 ){
			return;
		}
		//创建文件字节输入流
		BufferedInputStream bis = new BufferedInputStream(
									  new FileInputStream( srcFile ) );
		//把源文件分割成 每个(除了最后一个)大小都为1MB 的碎片文件
		byte[] buf = new byte[1024];//一次读1KB;
		int len = -1;
		long curSize = 0L;//表示当前碎片文件的大小
		int count = 1;//表示第 count 个碎片文件
		BufferedOutputStream bos = new BufferedOutputStream( 
									   new FileOutputStream( 
										   new File( targetDir,srcFile.getName() + count + ".frag" ) ) );
		while ( ( len = bis.read( buf ) ) != -1 ) {
			curSize += len ;
			if ( curSize >= size ) {
				//能到这里说明 当前 碎片文件 如果全部写入就会超出
				//所以要分割 
				curSize -= size; //下一个碎片文件中字节的大小
				//把当前碎片文件写满
				bos.write( buf, 0, (int)(len-curSize) );
				bos.close();
				
				//更新当前 碎片文件
				count++;
				bos = new BufferedOutputStream( 
						   new FileOutputStream( 
							   new File( targetDir,srcFile.getName() + count + ".frag" ) ) );
				bos.write( buf, (int)(len-curSize), (int)curSize );
			}else{
				bos.write( buf, 0, len );
			}
		}
		
		bis.close();
		bos.close();
	}
	/**
	 * 通过指定个数切割文件
	 * @param srcFile 被切割的文件
	 * @param targetDir 存放的目标文件夹
	 * @param i 指定个数
	 * @throws IOException 出错异常
	 */
	private void splitFileByNum(File srcFile, File targetDir, int i) throws IOException {
		//被切割的文件若不存在就返回
		if ( srcFile == null || !srcFile.exists() ) {
			return;
		}
		//判断存放的文件夹是否存在,如果不存在就创建
		if ( !targetDir.exists() ) {
			targetDir.mkdirs();
		}

		long fileSize = srcFile.length();
		//如果文件大小小于切割的个数 则无法切割
		if ( fileSize < i ) {
			return ;
		}
		long fragSize = fileSize/i;
		//创建文件字节输入流
		BufferedInputStream bis = new BufferedInputStream(
									  new FileInputStream( srcFile ) );
		byte[] buf = new byte[1024];
		int len = -1;
		long curSize = 0L; //表示当前文件的容量
		int count = 1;//表示 第 count 个文件碎片
		BufferedOutputStream bos = new BufferedOutputStream( 
									   new FileOutputStream( 
										   new File( targetDir, srcFile.getName() + count + ".frag" ) ) );
		while ( ( len = bis.read( buf ) ) != -1 ) {
			curSize += len;
			if ( curSize >= fragSize ) {
				count++;
				if (count <= i) {
					//能进入到这里说明 不是最后一个碎片文件
					curSize = (int) (curSize-fragSize);
					bos.write( buf, 0, (int)( len - curSize ) );
					bos.flush();
					bos.close();
					bos = new BufferedOutputStream( 
							   new FileOutputStream( 
								   new File( targetDir, srcFile.getName() + count + ".frag" ) ) );
					
					bos.write( buf, (int)( len - curSize ), (int) curSize );
				} else {
					bos.write( buf, 0, len );
				}
				
			}else{
				bos.write( buf, 0, len );
			}
		}
		bis.close();
		bos.close();
	}
	
	//文件合并
	@Test
	public void merge(){
		JFileChooser jfc = new JFileChooser();
		jfc.setFileSelectionMode( JFileChooser.DIRECTORIES_ONLY );
		int sel = jfc.showOpenDialog( null );
		if ( sel == JFileChooser.APPROVE_OPTION ) {
			//选择存放  要合并的 文件碎片 的文件夹
			File srcDir = jfc.getSelectedFile();
			//这里的文件名 需要 自己控制
			String targetFileName = "四大名著【精校合集】(红+西+水+三).rar";//这里可以指定哪个文件
			try {
				mergeFile( srcDir, targetFileName );
			} catch (IOException e) {
				JOptionPane.showMessageDialog(null, "文件合并失败!");
			}
		}
	}
	private void mergeFile(File srcDir, String targetFileName) throws IOException {
		//预防一下
		if( srcDir == null || !srcDir.exists() ){
			return ;
		}
		if ( targetFileName == null || "".equals(targetFileName) ) {
			return ;
		}
		File[] files = srcDir.listFiles();
		//这里需注意 要  排序  如果碎片文件个数 大于 等于 10个 合并就会出问题!!!
		Arrays.sort( files, new Comparator<File>() {

			@Override
			public int compare(File o1, File o2) {
				if ( o1.getName().length() > o2.getName().length() ) {
					return 1;
				} else if ( o1.getName().length() == o2.getName().length() ){
					return o1.getName().compareTo( o2.getName() );
				} else {
					return -1;
				}
			}
		} );
		ArrayList<FileInputStream> list = new ArrayList<FileInputStream>();
		//遍历该文件夹下所有文件
		int k = 1;
		for (int i = 0; i < files.length; i++) {
			//把符合的文件 加入 list
			if ( files[i].getName().contains( targetFileName + k + ".frag" ) ) {
				list.add( new FileInputStream( files[i] ) );
				k++;
			}
		}
		//如果没有碎片文件则退出
		if ( k == 1 ) {
			return ;
		}
		//通过 集合的工具类 Collections 获取 Enumeration 对象
		Enumeration<FileInputStream> en = Collections.enumeration( list );
		//通过 Enumeration 对象 构造 序列流 就是把多个输入流的出口合并成一个出口
		SequenceInputStream sis = new SequenceInputStream( en );
		//加Buffered 加快读取速度
		BufferedInputStream bis = new BufferedInputStream( sis );
		//加Buffered 加快写的速度
		BufferedOutputStream bos = new BufferedOutputStream( 
									   new FileOutputStream( 
										   new File( srcDir, targetFileName ) ) );
		byte[] buf = new byte[1024];
		int len = -1;
		while ( ( len = bis.read( buf ) ) != -1 ) {
			bos.write( buf, 0, len );
		}
		sis.close();
		bis.close();
		bos.close();
	}
}

猜你喜欢

转载自blog.csdn.net/qq_34928644/article/details/80219171