文件分割器的实现

记得读高中的时候特别喜欢看电子书,然而那时候还是2010年的时候,经济条件不好,买不起智能手机,只能使用一些山寨机,硬件设施较差,里面的txt文本阅读器只能读取大小不超过5M的电子书,然而网上的电子书基本上都超过了5M,为了能看这些书,只能在网上下载一个txt文件分割器,分割成小文件后,再下载到手机上,那时候还不懂编程,就觉得这个分割器是一个很神奇的东西。然而如今自己学了编程后发现一个文件分割器是十分容易实现的。

现在笔者就以Java中的IO流知识,实现一个文件分割器,当然知识实现了核心的代码,没有实现界面,毕竟Java中的Swing包做出来的界面不是那么好看,笔者对这一块知识也没有深入学习。

要想将一个文件分割,首先要知道将文件分成大小为多少的块(或者分成几块,笔者在这里只以每块的大小举例),例如我们要将一个大小为324个字节大小的文件分割成每块大小为100个字节的小文件,那么就需要将文件分成四块,且最后一块的实际大小为24。当然也会遇到这种情况,文件为324个字节,而要将文件分割成大小为400个字节的块,那么这个块的实际大小为324。


将文件分割好块后,接下来我们就需要将每一个小块写出到磁盘中。首先我们得用RandomAccessFile来读取文件到内存当中,利用seek方法设置从哪儿开始读取,然后用FileOutputStream来将读取到的内容写出到磁盘中。然而在写出的时候,会遇到这样一个问题:每次读取的长度len可能大于每一块的实际大小(例如该块的实际大小为100,而len却为120,这时候就不能将读取到的内容全部写出),因此需要判断,具体可以看下面的代码中的注释。


具体的代码如下:

  1. package com.tiantang.split;  
  2.   
  3. import java.io.BufferedOutputStream;  
  4. import java.io.File;  
  5. import java.io.FileOutputStream;  
  6. import java.io.IOException;  
  7. import java.io.OutputStream;  
  8. import java.io.RandomAccessFile;  
  9. import java.util.ArrayList;  
  10. import java.util.List;  
  11.   
  12. public class SplitFile {  
  13.       
  14.     //被分割文件的路径  
  15.     private String srcPath;  
  16.     //被分割的文件对象  
  17.     private File src;  
  18.     //分割的块数  
  19.     private int size;  
  20.     //每一块的大小  
  21.     private long blockSize;  
  22.     //每一块的实际大小  
  23.     private long actualBlockSize;  
  24.     //原文件的长度  
  25.     private long length;  
  26.     //分割得到的文件名的集合  
  27.     private List<String> splitFileNames=new ArrayList<String>();  
  28.       
  29.     public SplitFile(String srcPath,long blockSize){  
  30.         this.srcPath=srcPath;  
  31.         this.blockSize=blockSize;  
  32.         init();  
  33.     }  
  34.       
  35.     /** 
  36.      * 初始化文件分隔需要用到的参数 
  37.      */  
  38.     private void init(){  
  39.         //路径为空,则抛出异常  
  40.         if(srcPath==null){  
  41.             throw new RuntimeException("文件路径不合法");  
  42.         }  
  43.           
  44.         src=new File(srcPath);  
  45.           
  46.         //文件是否存在  
  47.         if(!src.exists()){  
  48.             throw new RuntimeException("文件不存在");  
  49.         }  
  50.         //是否是文件夹  
  51.         if(src.isDirectory()){  
  52.             throw new RuntimeException("不能分割文件夹");  
  53.         }  
  54.           
  55.         //如果文件存在  
  56.         length=src.length();  
  57.           
  58.         if(length<this.blockSize){  
  59.             this.blockSize=length;  
  60.         }  
  61.           
  62.         //计算分割的块数  
  63.         size=(int) ((length-1)/this.blockSize+1);  
  64.         //初始化分割后的文件名集合  
  65.         initSplitFileNames();  
  66.     }  
  67.   
  68.     /** 
  69.      * 初始化文件被分割后新生成文件的名字 
  70.      * 格式为:原文件名+第几块+扩展名 
  71.      */  
  72.     private void initSplitFileNames() {  
  73.         //文件的全名(包含后缀)  
  74.         String fileName=src.getName();  
  75.         //获得文件的扩展名前的分隔符‘.’  
  76.         int index=fileName.indexOf('.');  
  77.         //文件名的前缀  
  78.         String prefixName=fileName.substring(0,index );  
  79.         //文件名的后缀  
  80.         String extName=fileName.substring(index);  
  81.         for(int i=0;i<size;i++){  
  82.             splitFileNames.add(prefixName+(i+1)+extName);  
  83.         }  
  84.     }  
  85.       
  86.     /** 
  87.      * 文件分割的详细细节 
  88.      */  
  89.     public void split(){  
  90.         RandomAccessFile raf=null;  
  91.         OutputStream os=null;  
  92.         try {  
  93.             raf=new RandomAccessFile(src,"r");  
  94.             byte[] b=new byte[1024];  
  95.             int len=0;  
  96.             for(int i=0;i<size;i++){  
  97.                 raf.seek(blockSize*i);  
  98.                   
  99.                 //计算最后一块的实际大小  
  100.                 if(i==(size-1)){  
  101.                     actualBlockSize=length-blockSize*(size-1);  
  102.                 }else{  
  103.                     actualBlockSize=blockSize;  
  104.                 }  
  105.                   
  106.                 os=new BufferedOutputStream(new FileOutputStream(new File(src.getParent(),splitFileNames.get(i))));  
  107.                 while(-1!=(len=raf.read(b))){  
  108.                     //如果读取的长度已经超过了实际的长度,则只需要写实际长度的数据  
  109.                     if(len>=actualBlockSize){  
  110.                         os.write(b, 0, (int) actualBlockSize);  
  111.                         os.flush();  
  112.                         break;  
  113.                     }else{  
  114.                         os.write(b, 0, len);  
  115.                         os.flush();  
  116.                         actualBlockSize-=len;  
  117.                     }  
  118.                 }  
  119.             }  
  120.         } catch (Exception e) {  
  121.             e.printStackTrace();  
  122.         }finally{  
  123.             if(os!=null){  
  124.                 try {  
  125.                     os.close();  
  126.                 } catch (IOException e) {  
  127.                     e.printStackTrace();  
  128.                 }  
  129.             }  
  130.             if(raf!=null){  
  131.                 try {  
  132.                     raf.close();  
  133.                 } catch (IOException e) {  
  134.                     e.printStackTrace();  
  135.                 }  
  136.             }  
  137.               
  138.         }  
  139.     }  
  140.       
  141.     //测试  
  142.     public static void main(String[] args) {  
  143.         SplitFile sf=new SplitFile("F:\\test\\tiantang\\java1\\TestException.java",200);  
  144.         sf.split();  
  145.     }  
  146.   
  147. }  
package com.tiantang.split;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.List;

public class SplitFile {
	
	//被分割文件的路径
	private String srcPath;
	//被分割的文件对象
	private File src;
	//分割的块数
	private int size;
	//每一块的大小
	private long blockSize;
	//每一块的实际大小
	private long actualBlockSize;
	//原文件的长度
	private long length;
	//分割得到的文件名的集合
	private List<String> splitFileNames=new ArrayList<String>();
	
	public SplitFile(String srcPath,long blockSize){
		this.srcPath=srcPath;
		this.blockSize=blockSize;
		init();
	}
	
	/**
	 * 初始化文件分隔需要用到的参数
	 */
	private void init(){
		//路径为空,则抛出异常
		if(srcPath==null){
			throw new RuntimeException("文件路径不合法");
		}
		
		src=new File(srcPath);
		
		//文件是否存在
		if(!src.exists()){
			throw new RuntimeException("文件不存在");
		}
		//是否是文件夹
		if(src.isDirectory()){
			throw new RuntimeException("不能分割文件夹");
		}
		
		//如果文件存在
		length=src.length();
		
		if(length<this.blockSize){
			this.blockSize=length;
		}
		
		//计算分割的块数
		size=(int) ((length-1)/this.blockSize+1);
		//初始化分割后的文件名集合
		initSplitFileNames();
	}

	/**
	 * 初始化文件被分割后新生成文件的名字
	 * 格式为:原文件名+第几块+扩展名
	 */
	private void initSplitFileNames() {
		//文件的全名(包含后缀)
		String fileName=src.getName();
		//获得文件的扩展名前的分隔符‘.’
		int index=fileName.indexOf('.');
		//文件名的前缀
		String prefixName=fileName.substring(0,index );
		//文件名的后缀
		String extName=fileName.substring(index);
		for(int i=0;i<size;i++){
			splitFileNames.add(prefixName+(i+1)+extName);
		}
	}
	
	/**
	 * 文件分割的详细细节
	 */
	public void split(){
		RandomAccessFile raf=null;
		OutputStream os=null;
		try {
			raf=new RandomAccessFile(src,"r");
			byte[] b=new byte[1024];
			int len=0;
			for(int i=0;i<size;i++){
				raf.seek(blockSize*i);
				
				//计算最后一块的实际大小
				if(i==(size-1)){
					actualBlockSize=length-blockSize*(size-1);
				}else{
					actualBlockSize=blockSize;
				}
				
				os=new BufferedOutputStream(new FileOutputStream(new File(src.getParent(),splitFileNames.get(i))));
				while(-1!=(len=raf.read(b))){
					//如果读取的长度已经超过了实际的长度,则只需要写实际长度的数据
					if(len>=actualBlockSize){
						os.write(b, 0, (int) actualBlockSize);
						os.flush();
						break;
					}else{
						os.write(b, 0, len);
						os.flush();
						actualBlockSize-=len;
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			if(os!=null){
				try {
					os.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if(raf!=null){
				try {
					raf.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			
		}
	}
	
	//测试
	public static void main(String[] args) {
		SplitFile sf=new SplitFile("F:\\test\\tiantang\\java1\\TestException.java",200);
		sf.split();
	}

}
这样我们就实现了文件的分割,至于文件的合并的思路则是依次将文件读到内存中,然后将文件利用 new FileOutputStream(destPath,true)将文件写出,注意该对象的第二个参数需要指定为true,只要这样才能是将文件追加写入,否则将是覆盖
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值