package lesson4;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Collections;
import java.util.PriorityQueue;


public class HuffmanCode {
	
	private String path;//文件的输入路径
	private byte byteCount[] = new byte[256];//每个字节的计数
	hfmNode root=null;//定义的根节点
	
	//private int fileLen;//input文件长度
	private Code SaveCode[]=new Code[256];
	
    /**
     * 写一个构造器来传入path
     * @param path 文件路径
     */
    public HuffmanCode(String path){
    	this.path=path;
    	
		for (int i=0;i<256;i++){//频率清零 初始化
			byteCount[i]=0;
			Code t = new Code();
			t.n=0;
			t.node="";
			SaveCode[i]=t;
		}
    }
    
    /**
     * 读入文件
     */
    public void readFile(){
		try {
			// 创建文件输入流
			java.io.FileInputStream fis = new java.io.FileInputStream(path);
			//读入所有的文件字节
			while(fis.available()>0){
				int i=fis.read();
				byteCount[i]++;
			}
			System.out.println("读入文件");
			//构建哈弗曼树
			createTree();
			//生成编码
			getMB(root,"");
			fis.close();//关闭文件流
		} catch (Exception e) {
			e.printStackTrace();
		}
    }

    /**
     * 输出压缩文件
     */
    public void writeFile(){
    	try {
    		// 创建文件输入流
			java.io.FileInputStream fis = new java.io.FileInputStream(path);
			// 创建文件输出流
			java.io.FileOutputStream fos = new java.io.FileOutputStream(path+".stzip");
           //写出每一个编码的长度
            for (int i=0;i<256;i++){
            	fos.write(SaveCode[i].n);
            }  
            
            
            //////////////////////////////////////////写入每一个字节锁对应的 String编码
			int count=0;//记录中转的字符个数
			int i=0;//第i个字节
			String writes ="";
			String tranString="";//中转字符串
			String waiteString;//保存所转化的所有字符串
			while((i<256)||(count>=8)){
				//如果缓冲区的等待写入字符大于8
				if (count>=8){
					waiteString="";//清空要转化的的码
					for (int t=0;t<8;t++){
			        	waiteString=waiteString+writes.charAt(t);	
				     }
				
					//将writes前八位删掉
					if (writes.length()>8){
					  tranString="";
					  for (int t=8;t<writes.length();t++){
					     	tranString=tranString+writes.charAt(t);
					     }
					  writes="";
					  writes=tranString;
					  }else{
						  writes="";
					  }
					
					  count=count-8;//写出一个8位的字节
					  int intw=changeString(waiteString);//得到String转化为int
			          //写入文件
					  fos.write(intw);
				}else{
					//得到地i个字节的编码信息,等待写入
					count=count+SaveCode[i].n;
					writes=writes+SaveCode[i].node;
					i++;
				}
			}
			///////////////////////////////////////////////////////////////////
			//把所有编码没有足够8的整数倍的String补0使得足够8的整数倍,再写入
			if (count>0){
				waiteString="";//清空要转化的的码
				for (int t=0;t<8;t++){
					if (t<writes.length()){
						waiteString=waiteString+writes.charAt(t);	
					}else{
						waiteString=waiteString+'0';
					}
				}
				fos.write(changeString(waiteString));//写入
				System.out.println("写入了->"+waiteString);
			}
			//////////////////////////////////
			//再次读入文件的信息,对应每一个字节写入编码
			count=0;
			writes ="";
			tranString="";
			int idata=fis.read();
			//文件没有读完的时候
			while ((fis.available()>0)||(count>=8)){
				//如果缓冲区的等待写入字符大于8
				if (count>=8){
					waiteString="";//清空要转化的的码
					for (int t=0;t<8;t++){
			        	waiteString=waiteString+writes.charAt(t);	
				     }
				   
				   //将writes前八位删掉
				   if (writes.length()>8){
				     tranString="";
				     for (int t=8;t<writes.length();t++){
				     	tranString=tranString+writes.charAt(t);
				       }
				      writes="";
				     writes=tranString;
				    }else{
					  writes="";
				    }
				   
				   
				  count=count-8;//写出一个8位的字节
				  int intw=changeString(waiteString);
				  fos.write(intw);//写到文件中区
				}else{
					//读入idata字节,对应编码写出信息
					count=count+SaveCode[idata].n;
					writes=writes+SaveCode[idata].node;
					idata=fis.read();
				}
			}
			count=count+SaveCode[idata].n;
			writes=writes+SaveCode[idata].node;
			//把count剩下的写入
			 int endsint=0;
			 if (count>0){
				waiteString="";//清空要转化的的码
				for (int t=0;t<8;t++){
					if (t<writes.length()){
					waiteString=waiteString+writes.charAt(t);	
				}else{
					waiteString=waiteString+'0';
					endsint++;
					}
				}
				fos.write(changeString(waiteString));//写入所补的0
				System.out.println("写入了->"+waiteString+"int:"+endsint);
				
			 }
			 //写一个n记录所补0的个数
			fos.write(endsint);
			System.out.println("压缩完毕!");  
			fis.close();//关闭文件
			fos.close();
    	} catch (Exception ef) {
			ef.printStackTrace();
		}
    }
    
    
    
    /**
     * 将一个八位的字符串转成一个整数
     * @param s
     * @return
     */
    public int changeString(String s){
    	return ((int)s.charAt(0)-48)*128+((int)s.charAt(1)-48)*64+((int)s.charAt(2)-48)*32
    	        +((int)s.charAt(3)-48)*16+((int)s.charAt(4)-48)*8+((int)s.charAt(5)-48)*4
    	        +((int)s.charAt(6)-48)*2+((int)s.charAt(7)-48);
    }
    
    
    /**
     * 使用优先队列构建哈弗曼树
     */
    public void createTree(){
	   //优先队列
	  PriorityQueue<hfmNode> nodeQueue = new PriorityQueue<hfmNode>();
	  
	   //把所有的节点都加入到 队列里面去
		for (int i=0;i<256;i++){
			if(byteCount[i]!=0){
				hfmNode node = new hfmNode(i,byteCount[i]);
				nodeQueue.add(node);//加入节点
			}
		}
		//构建哈弗曼树
		while(nodeQueue.size()>1)
        {
			hfmNode min1 = nodeQueue.poll();//获取队列头
			hfmNode min2 = nodeQueue.poll();
			
			hfmNode result = new hfmNode(0,min1.times+min2.times);
			result.lChild=min1;
			result.rChild=min2;
            nodeQueue.add(result);//加入合并节点
        }
	    root=nodeQueue.peek(); //得到根节点
    }
    
    
    
    /**
     * 获得叶子节点的哈弗曼编码 
     * @param root 根节点
     * @param s
     */
    public void getMB(hfmNode root,String s){
        if ((root.lChild==null)&&(root.rChild==null)){
     	    Code hc=new Code();
     	    hc.node=s;
     	    hc.n=s.length();
     	    System.out.println("节点"+root.data+"编码"+hc.node);
     	    SaveCode[root.data]=hc;//保存字节  root.data 的编码 HC
         }
     	if (root.lChild!=null){//左0 右 1
     		getMB(root.lChild,s+'0');
     	}
     	if (root.rChild!=null){
     		getMB(root.rChild,s+'1');
      	}
     }
}
最近下载更多
wanglinddad  LV54 2022年5月7日
17343991667  LV1 2021年12月14日
一个好人520  LV10 2021年9月29日
675104182  LV14 2020年9月22日
dybtom  LV10 2019年6月28日
zhezero  LV2 2018年1月11日
南峋丶  LV18 2016年12月29日
seandtx  LV1 2016年4月21日
yccycc  LV1 2015年12月31日
zw5097  LV23 2015年12月14日
最近浏览更多
666ing  LV2 2022年12月16日
wanglinddad  LV54 2022年4月28日
17343991667  LV1 2021年12月14日
一个好人520  LV10 2021年9月29日
yangctz  LV24 2021年9月3日
675104182  LV14 2020年9月21日
asd45211  LV9 2020年6月10日
菜鸡回车  LV1 2020年5月15日
wei112233  LV15 2020年5月11日
安添霁  LV1 2020年4月30日
顶部 客服 微信二维码 底部
>扫描二维码关注最代码为好友扫描二维码关注最代码为好友