标签:不能 static write 设置 fonts pre cto lock ring
记得读高中的时候特别喜欢看电子书,然而那时候还是2010年的时候,经济条件不好,买不起智能手机,只能使用一些山寨机,硬件设施较差,里面的txt文本阅读器只能读取大小不超过5M的电子书,然而网上的电子书基本上都超过了5M,为了能看这些书,只能在网上下载一个txt文件分割器,分割成小文件后,再下载到手机上,那时候还不懂编程,就觉得这个分割器是一个很神奇的东西。然而如今自己学了编程后发现一个文件分割器是十分容易实现的。
现在笔者就以Java中的IO流知识,实现一个文件分割器,当然知识实现了核心的代码,没有实现界面,毕竟Java中的Swing包做出来的界面不是那么好看,笔者对这一块知识也没有深入学习。
要想将一个文件分割,首先要知道将文件分成大小为多少的块(或者分成几块,笔者在这里只以每块的大小举例),例如我们要将一个大小为324个字节大小的文件分割成每块大小为100个字节的小文件,那么就需要将文件分成四块,且最后一块的实际大小为24。当然也会遇到这种情况,文件为324个字节,而要将文件分割成大小为400个字节的块,那么这个块的实际大小为324。
将文件分割好块后,接下来我们就需要将每一个小块写出到磁盘中。首先我们得用RandomAccessFile来读取文件到内存当中,利用seek方法设置从哪儿开始读取,然后用FileOutputStream来将读取到的内容写出到磁盘中。然而在写出的时候,会遇到这样一个问题:每次读取的长度len可能大于每一块的实际大小(例如该块的实际大小为100,而len却为120,这时候就不能将读取到的内容全部写出),因此需要判断,具体可以看下面的代码中的注释。
具体的代码如下:
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,只要这样才能是将文件追加写入,否则将是覆盖
标签:不能 static write 设置 fonts pre cto lock ring
原文地址:http://blog.csdn.net/qq_34436819/article/details/54311506