IO学习(十七)文件的分割与合并
2016-05-22 00:39
267 查看
目的:将文件分割成数个部分,然后再将它们合并起来
首先文件的分割,有下面几个要点
1.先要确定的两个因素就是,分成多少块,每块多大,那么最后一块的大小不一定刚好能是你规定的每小块的大小,那么最后一块的大小就比较特殊,它等于文件总大小(块数-1)乘以每块大小
2.在操作源文件到目的文件,即被分割文件到分割文件时,实际上就是文件的拷贝过程
3.最关键的问题是如何控制文件输入流,它必须按照指定的位置读取每一个分块
比如,我有142k大小的文件,要将他们分割成3块,规定每块大小为50,那么我将第一块内容读取的时候,是从0-50K
当读第二快内容时就变成了50-100K,那么如何控制读取范围?
这里就需要用到RandomAccessFile类,它提供了一个seek方法,可以指定读取的开始位置
文件的合并就是将那些分块重新组合在一起,比文件分割考虑的因素少,这里提供了两种不同的方式进行文件合并,其实也就是关于输入流做出的改变,详细见下文,合并从小块文件到大文件,其实也就是文件追加输出
本着OOP的设计思想,将对文件的信息和操作方法封装成一个类 SplitFile
这个类包含了关于文件的一些基本信息,文件的路径,大小,名称等,以及为了分割需要的一些信息,分割块数,每块的大小,分割文件所在的目录文件,各自的名称等,下面开始一步一步实现代码
1.类属性+构造方法
在构造方法运行结束后,初始化也结束,关于每块大小可以在创建对象的时候设置,也可以使用默认的1024
2.初始化分割信息
确定分割块数,先得到文件长度length
size=(int)(Math.ceil(length*1.0/this.blockSize));
确定部分文件的名称
由于将所有小文件的名称存放在List中,所以这里用一个for循环,往List中添加元素
其中destPath是存放部分文件的目录
for(int i=0;i<this.size;i++){
this.blockPath.add(destPath+"/"+this.fileName+".part"+i);
}
3.文件的分割
这里需要两个很关键的值,beginPos和actualBlockSize,每个部分文件开始的位置,以及它的大小
由于每一个分块这些信息都不完全相同,所以需要分别处理
使用for循环遍历所有的块,需要注意的是,我们的size是向下取整,也就是说当计算的值为3.6时,size的值为3,但是这里的i从0开始,所以一切正常
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;
}
spiltDetail方法其实就是真正文件分割的过程,其实也就是文件拷贝,4个步骤
选择目标文件和源文件;选择输入输出流;进行拷贝;关闭流
在拷贝过程中,需要注意不能一直都以固定的缓冲长度来写出数据,需要进行判断
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;
}
}
文件的合并就比较简单了,第二种方法中用到了SequenceInputStream类,将很多个输入流集中在一起,只所有有很多个输入流是由于每一个部分文件对应一个输入流
要使用这个类就要先有一个集合,这里用Vector<InputStream>创建一个带泛型的Vector对象
使用for循环将文件输入流添加到容器中,然后构建SequenceInputStream对象
SequenceInputStream sis = new SequenceInputStream(vi.elements());
为了增强代码的健壮性,还添加了一些判断,下面是全部代码
首先文件的分割,有下面几个要点
1.先要确定的两个因素就是,分成多少块,每块多大,那么最后一块的大小不一定刚好能是你规定的每小块的大小,那么最后一块的大小就比较特殊,它等于文件总大小(块数-1)乘以每块大小
2.在操作源文件到目的文件,即被分割文件到分割文件时,实际上就是文件的拷贝过程
3.最关键的问题是如何控制文件输入流,它必须按照指定的位置读取每一个分块
比如,我有142k大小的文件,要将他们分割成3块,规定每块大小为50,那么我将第一块内容读取的时候,是从0-50K
当读第二快内容时就变成了50-100K,那么如何控制读取范围?
这里就需要用到RandomAccessFile类,它提供了一个seek方法,可以指定读取的开始位置
文件的合并就是将那些分块重新组合在一起,比文件分割考虑的因素少,这里提供了两种不同的方式进行文件合并,其实也就是关于输入流做出的改变,详细见下文,合并从小块文件到大文件,其实也就是文件追加输出
本着OOP的设计思想,将对文件的信息和操作方法封装成一个类 SplitFile
这个类包含了关于文件的一些基本信息,文件的路径,大小,名称等,以及为了分割需要的一些信息,分割块数,每块的大小,分割文件所在的目录文件,各自的名称等,下面开始一步一步实现代码
1.类属性+构造方法
在构造方法运行结束后,初始化也结束,关于每块大小可以在创建对象的时候设置,也可以使用默认的1024
public class SplitFile { //文件路径 private String filePath; //文件名称 private String fileName; //文件大小 private long length; //块数 private int size; //每块大小 private long blockSize; //每块名称 private List<String> blockPath; //分割后的目录 private String destPath; public SplitFile() { this.blockPath=new ArrayList<String>(); } public SplitFile(String filePath,String destPath){ this(filePath,1024,destPath); } public SplitFile(String filePath, long blockSize,String destPath) { this(); this.filePath = filePath; this.blockSize = blockSize; this.destPath=destPath; init(); } }
2.初始化分割信息
确定分割块数,先得到文件长度length
size=(int)(Math.ceil(length*1.0/this.blockSize));
确定部分文件的名称
由于将所有小文件的名称存放在List中,所以这里用一个for循环,往List中添加元素
其中destPath是存放部分文件的目录
for(int i=0;i<this.size;i++){
this.blockPath.add(destPath+"/"+this.fileName+".part"+i);
}
3.文件的分割
这里需要两个很关键的值,beginPos和actualBlockSize,每个部分文件开始的位置,以及它的大小
由于每一个分块这些信息都不完全相同,所以需要分别处理
使用for循环遍历所有的块,需要注意的是,我们的size是向下取整,也就是说当计算的值为3.6时,size的值为3,但是这里的i从0开始,所以一切正常
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;
}
spiltDetail方法其实就是真正文件分割的过程,其实也就是文件拷贝,4个步骤
选择目标文件和源文件;选择输入输出流;进行拷贝;关闭流
在拷贝过程中,需要注意不能一直都以固定的缓冲长度来写出数据,需要进行判断
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;
}
}
文件的合并就比较简单了,第二种方法中用到了SequenceInputStream类,将很多个输入流集中在一起,只所有有很多个输入流是由于每一个部分文件对应一个输入流
要使用这个类就要先有一个集合,这里用Vector<InputStream>创建一个带泛型的Vector对象
使用for循环将文件输入流添加到容器中,然后构建SequenceInputStream对象
SequenceInputStream sis = new SequenceInputStream(vi.elements());
为了增强代码的健壮性,还添加了一些判断,下面是全部代码
public class SplitFile { //文件路径 private String filePath; //文件名称 private String fileName; //文件大小 private long length; //块数 private int size; //每块大小 private long blockSize; //每块名称 private List<String> blockPath; //分割后的目录 private String destPath; public SplitFile() { this.blockPath=new ArrayList<String>(); } public SplitFile(String filePath,String destPath){ this(filePath,1024,destPath); } public SplitFile(String filePath, long blockSize,String destPath) { this(); this.filePath = filePath; this.blockSize = blockSize; this.destPath=destPath; init(); } /** * 初始化操作,确定块数 */ public void init(){ File src=null; //如果文件民为空或者文件不存在,直接return if(null==this.filePath || !( (src=new File(this.filePath)).exists())){ return ; } //如果是一个文件夹,直接return if(src.isDirectory()){ return; } //得到文件实际大小与名称 this.length=src.length(); this.fileName=src.getName(); //如果每块大小大于文件大小,则修改每块大小 if(this.blockSize>length){ this.blockSize=length; } //计算块数,向下取整 size=(int)(Math.ceil(length*1.0/this.blockSize)); } /** * 初始化部分文件名称 */ private void initPathName(String destPath){ for(int i=0;i<this.size;i++){ this.blockPath.add(destPath+"/"+this.fileName+".part"+i); System.out.println("initpathname"); } } /** * 文件的分割 * @param destPath 分割文件存放目录 */ public void split(String destPath){ //设置路径 initPathName(destPath); 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){ File src=new File(filePath); File dest=new File(this.blockPath.get(idx)); RandomAccessFile raf=null; BufferedOutputStream bos=null; try { raf = new RandomAccessFile(src, "r"); bos = new BufferedOutputStream(new FileOutputStream(dest)); raf.seek(beginPos); int len = 0; byte[] flush = new byte[1024]; 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) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); }finally{ try { bos.close(); raf.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } /** * 文件合并 * @param args */ public void mergeFile1(String destPath){ File dest=new File(destPath); BufferedInputStream bis = null; BufferedOutputStream bos = null; try { for (int i = 0; i < this.blockPath.size(); i++) { bis = new BufferedInputStream(new FileInputStream(new File( blockPath.get(i)))); // 设置为追加 bos = new BufferedOutputStream(new FileOutputStream(dest, true)); int len = 0; byte[] flush = new byte[1024]; while (-1 != (len = bis.read(flush))) { bos.write(flush, 0, len); } bos.flush(); bis.close(); } } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally{ try { bos.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } /** * 文件合并2 * 使用SequenceInputStream * @param args */ public void mergeFile2(String destPath){ File dest=new File(destPath); SequenceInputStream sis=null; BufferedOutputStream bos = 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(blockPath.get(i))))); } // 设置为追加 bos = new BufferedOutputStream(new FileOutputStream(dest, true)); sis = new SequenceInputStream(vi.elements()); int len = 0; byte[] flush = new byte[1024]; while (-1 != (len = sis.read(flush))) { bos.write(flush, 0, len); } bos.flush(); sis.close(); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally{ try { bos.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
相关文章推荐
- DT大数据梦工厂Spark定制班笔记(006)
- 怎么通过git工具把代码上传到新浪云里去
- Linux下开发环境(gcc/g++/makefile/gdb)
- Android基础学习之ListView优化及栏目分类
- HDU-1166 ( 敌兵布阵 )
- OGG-01232 问题解决
- linux超级块和inode 详解 和 df 、du 命令详解与环境变量
- ELK(ElasticSearch, Logstash, Kibana)搭建实时日志分析平台
- 【拓扑排序】[2016"百度之星" - 初赛(Astar Round2A)]Gym Class
- HDU 1070 - Milk
- zabbix 二 zabbix agent 客户端
- (最全版)Java与C++的异同
- JavaScript作用域
- Android WebView使用详解包括js互调(by 星空武哥)
- SQL之高级联结查询
- 一个奇怪的崩溃问题
- Centos6安装桌面后无法使用键盘和鼠标
- java 内存回收机制和算法(只有跳转链接)
- JavaScript DOM用document.createElement()生成元素,用seAttribute()函数设置属性值
- JavaScript DOM用document.createElement()生成元素,用seAttribute()函数设置属性值