壓縮的過程

壓縮:

   1.壓縮思路:

1.把文件的字符讀出來,記錄出現過的字符及其出現的次數。構造相應的結點。

2.把結點組建成一棵哈夫曼樹,並獲得哈夫曼編碼。

3.利用哈夫曼編碼,寫入頭文件和文件內容。

   2.讀字符,存隊列

1.讀取文件信息,存放於數組之中,下標作爲ask碼值


public int[] countChar(String path){
			File file = new File(path);//根據文件地址創建文件對象
			int[] c = new int[256];

			for(int i=0;i<c.length;i++){
				c[i]=0;
			}
			try {
				//創建輸出流對象
				InputStream is = new FileInputStream(file);
				//一個一個的讀出
				while(is.available()>0){
					int i = is.read();   //將文件讀入到 數組 中
					c[i]++;
				}
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			} 
			return c;
		}
 

2.構建結點,建造樹。

Queue q =  new Queue();//實例化隊列對象
		HFMTree tree = new HFMTree();//實力化一個樹對象
		//用於記錄文件中出現過的字符的次數,下標指 ask碼值對應的字符 
		int[] ch = this.countChar(path);
		//利用次數數組創建結點對象,加入隊列
		for(int i=0;i<ch.length;i++){
			if(ch[i]!=0){
				//如果出現過該字符,則創建結點,加入隊列
				Node node = new Node(((char)i)+"", ch[i]);
				q.add(node);
			}
		}
		tree.creatTree(q);  //利用結點構建樹
		q = tree.ergodic(tree.getRoot(),""); //遍歷樹,給結點繪製對應的編碼,存儲於隊列之中
 

   3.第三步驟:

1.頭文件

1.頭文件包括出現字符的編碼。

@  隊列長度(int) 

@  文件末尾補零情況   

@  每一個隊列元素    

@字符

@編碼長度

@最後一次補零的個數

@編碼的具體信息

這是頭文件的內容格式,也就是必要的一些內容,因爲文件本身是一個獨立的個體,要考慮到之後能夠讀取出來,所以必須要存入如上戲信息,不然在打開時,因爲不知道文件信息,而無法打開。

2.寫入頭文件

public void compressFile(String path,String newpath){
		File file = new File(path);  //將地址解析成具體的文件
		File newfile = new File(newpath);  //將地址解析成具體的文件
		
		try {
			//創建輸出流對象
			InputStream bis = new FileInputStream(file);
			BufferedInputStream is = new BufferedInputStream(bis);
			//創建輸入流對象 
			OutputStream bos = new FileOutputStream(newfile);
			BufferedOutputStream os = new BufferedOutputStream(bos);
			/***將隊列讀入文件***/
			os.write(q.size());                                              
			//文件最後補零的情況
			int addzero = 0,cache = 0;
			for(int i=0;i<q.size();i++){
				//文件長度 = 字符次數   * 編碼長度
				cache += q.get(i).getCount()*q.get(i).getSymbol().length(); 
			}
			addzero = 8-cache%8; //文件補零的情況
			/***寫入文件末尾補零情況****/
			os.write(addzero);
			/****寫入編碼信息*****/
			for(int i=0;i<q.size();i++){
				//獲取信息
				int xchar = q.get(i).getData().charAt(0); 
				int xsize = q.get(i).getSymbol().length()/8+1;
				int xzero = 8-q.get(i).getSymbol().length()%8;
				//寫入信息
				os.write(xchar);//字符
				os.write(xsize);//長度
				os.write(xzero);//補零個數
				//寫入編碼
				String string = q.get(i).getSymbol();
				String waitString = ""; //用來緩存的字符串
				//寫入編碼的前幾位
				for(int j=0;j<xsize-1;j++){
					waitString = "";
					waitString = string.substring(0, 8);
					string = string.substring(8);
					int xString = changeString(waitString);
					os.write(xString);
				}
				//寫入編碼最後一位
				for(int j=0;j<xzero;j++){
					string += "0";
				}
				int xString = changeString(string);
				os.write(xString);//寫入編碼內容
			}
 

3.寫入文件內容

String writeString = ""; 
			while(is.available()>0){
				int i = is.read();   //將文件讀出來
				for(int j=0;j<q.size();j++){//用循環找到對應的字符編碼
					boolean bool = false; //需要尋找的字符還未找到
					//如果找到了
					if(q.get(j).getData().equals((((char)i)+""))){
						int x=0;
						while(true){
							writeString += q.get(j).getSymbol().charAt(x)+"";
							x++;
							//如果是因爲溢出
							if(writeString.length()==8){
								int xString = changeString(writeString);
								os.write(xString);             //寫入一個字節
								writeString = "";
							}
							//如果是因爲數字位數不足
							if(x==q.get(j).getSymbol().length()){
								bool = true;
								break;
							}
						}
					}//如果找到文件
					if(bool==true){
						break;
					}
				}
			}
			//對最後一個經行處理
			if(writeString.length()>0){
				int x = 8-writeString.length();
				for(int i=0;i<x;i++){
					writeString += "0";
				}
				int xString = changeString(writeString);
				os.write(xString);
			}
			os.close();//關閉輸出流
			is.close();//關閉輸入流
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} 
	}	
 

這樣就對一個文本文件實現了壓縮功能。剩下的解壓,無非是根據文件信息,一步一步經行反步驟,解壓開來。這種壓縮方式在我的測試中發現有一個缺點,當文件末尾是字符時,就正常運行,當文件最後一個是漢字時,最後一個漢字會被改變,所以這一點暫時還沒考慮到,留着廣大讀者去思考吧。呵呵!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章