記得讀高中的時候特別喜歡看電子書,但是那時候還是2010年的時候,經濟條件不好,買不起智能手機,只能使用1些山寨機,硬件設施較差,里面的txt文本瀏覽器只能讀取大小不超過5M的電子書,但是網上的電子書基本上都超過了5M,為了能看這些書,只能在網上下載1個txt文件分割器,分割成小文件后,再下載得手機上,那時候還不懂編程,就覺得這個分割器是1個很奇異的東西。但是如今自己學了編程后發現1個文件分割器是10分容易實現的。
現在筆者就以Java中的IO流知識,實現1個文件分割器,固然知識實現了核心的代碼,沒有實現界面,畢竟Java中的Swing包做出來的界面不是那末好看,筆者對這1塊知識也沒有深入學習。
要想將1個文件分割,首先要知道將文件分成大小為多少的塊(或分成幾塊,筆者在這里只以每塊的大小舉例),例如我們要將1個大小為324個字節大小的文件分割成每塊大小為100個字節的小文件,那末就需要將文件分成4塊,且最后1塊的實際大小為24。固然也會遇到這類情況,文件為324個字節,而要將文件分割成大小為400個字節的塊,那末這個塊的實際大小為324。
將文件分割好塊后,接下來我們就需要將每個小塊寫出到磁盤中。首先我們得用RandomAccessFile來讀取文件到內存當中,利用seek方法設置從哪兒開始讀取,然后用FileOutputStream來將讀取到的內容寫出到磁盤中。但是在寫出的時候,會遇到這樣1個問題:每次讀取的長度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⑴)/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); //計算最后1塊的實際大小 if(i==(size⑴)){ actualBlockSize=length-blockSize*(size⑴); }else{ actualBlockSize=blockSize; } os=new BufferedOutputStream(new FileOutputStream(new File(src.getParent(),splitFileNames.get(i)))); while(⑴!=(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)將文件寫出,注意該對象的第2個參數需要指定為true,只要這樣才能是將文件追加寫入,否則將是覆蓋
上一篇 shc加密shell原理