Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 589|回复: 0

[JavaIO学习]学习哈夫曼压缩与解压缩(3)

[复制链接]
  • TA的每日心情
    开心
    2021-3-12 23:18
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2014-11-2 23:58:24 | 显示全部楼层 |阅读模式
    继续前文"哈夫曼压缩与解压缩学习笔记(二)
        http://www.java3z.com/cwbwebhome/article/article8/83579.html
       
         下面两个类主要是根据字节计数器的统计结果,创建哈夫曼树,计算字节的哈夫曼编码及由哈夫曼编码在树中找节点,往文件中写码表,读码表.
       
    (5)HuffNode.java
       

        //哈夫曼树节点
    public class HuffNode  implements Comparable<HuffNode>
    {
        public int value;//节点的字节值
        public int weight;//节点的权值(字节出现的频率)
       
        public int compareTo( HuffNode rhs )
        {
            return weight - rhs.weight;
        }
       
        HuffNode left;//左节点
        HuffNode right;//右节点
        HuffNode parent;//父节点
       
        HuffNode( int v, int w, HuffNode lt, HuffNode rt, HuffNode pt )
        {
            value = v; weight = w; left = lt; right = rt; parent = pt;
        }
    }[/code] (6)HuffmanTree.java
       

       

        //哈夫曼树
    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.io.IOException;
    import java.util.PriorityQueue;
    import java.io.*;
    public class HuffmanTree {
       
        public long charCountSum;
        private CharCounter theCounts;//字节计数器
        //存放哈夫曼树的所有节点,字节i对应的节点是theOndes
        private HuffNode [ ] theNodes = new HuffNode[ BitUtils.DIFF_BYTES + 1 ];//256+1
        private HuffNode root;//哈夫曼树的根节点
        public HuffmanTree( )
        {
            theCounts = new CharCounter( );
            root = null;
        }
       
        public HuffmanTree( CharCounter cc )//构造函数
        {
            theCounts = cc;//注入字节计数器
            root = null;
            createTree( );//创建哈夫曼树
            charCountSum=charCountSum();//总的字节数(原文件的大小)
        }
       
        public static final int ERROR = -3;
        public static final int INCOMPLETE_CODE = -2;
        public static final int END = BitUtils.DIFF_BYTES;
       
                  
        //根据字节计数器的统计结果,创建哈夫曼树,
        private void createTree( )
        {
            PriorityQueue<HuffNode> pq = new PriorityQueue<HuffNode>( );//优先队列
            
      for( int i = 0; i < BitUtils.DIFF_BYTES; i++ )//对0---256之间的每一个字节构造哈夫曼节点
                if ( theCounts.getCount( i ) > 0 )
                {
                    //以字节值,字节在原文件中出现的次数(权)构建哈夫曼节点
                    HuffNode newNode = new HuffNode( i,
                           theCounts.getCount( i ), null, null, null );
                    theNodes[ i ] = newNode;//保存节点
                    pq.add( newNode );//节点加入优先队列
                }
                  
            while( pq.size( ) > 1 )//创建哈夫曼树
            {
                HuffNode n1 = pq.remove( );
                HuffNode n2 = pq.remove( );
                HuffNode result = new HuffNode( INCOMPLETE_CODE,
                                      n1.weight + n2.weight, n1, n2, null );
                n1.parent = n2.parent = result;
                pq.add( result );
            }      
            
            root = pq.element( );//返回哈夫曼树的根
        }
      
        public int[] getCode( int ch )//以整型数组的形式返回字节ch的哈夫曼编码,如{1,1,0},{1,1,1}
        {
            HuffNode current = theNodes[ ch ];//找到与ch对应的节点
            if( current == null )
                return null;
                
            String v = "";
            HuffNode par = current.parent;//ch的直接父节点
            
            while ( par != null )//找ch的父节点,一直到根
            {
                if( par.left == current )//顺带写出ch的哈夫曼码
                    v = "0" + v;
                else
                    v = "1" + v;
                current = current.parent;
                par = current.parent;
            }
          
            int [ ] result = new int[ v.length( ) ];
            for( int i = 0; i < result.length; i++ )
                result[ i ] = v.charAt( i ) == "0" ? 0 : 1;
                
            return result;//以整型数组的形式返回字节ch的哈夫曼编码
        }
       
       
        public int getChar( String code )//由字节的哈夫曼编码求出此字节
        {
            HuffNode p = root;
            for( int i = 0; p != null && i < code.length( ); i++ )
                if( code.charAt( i ) == "0" )
                    p = p.left;
                else
                    p = p.right;
                   
            if( p == null )
                return ERROR;
                
            return p.value;            
        }
        //解压缩的关键方法
    //从BitInputStream流中一位一位的读(然后在树中找节点),直到读到一个哈夫曼编码,返回哈夫曼编码对应的字节值
        public int getChar(BitInputStream bips) throws IOException
        {
                HuffNode p = root;//哈夫曼树的根节点
                while( p!=null)
                {       
                        int bit=bips.readBit();//从流中读一位
                        if(bit==-1)
                                return -1;
                    if(bit == 0 )//如果是0,在哈夫曼树中向左找
                            p =p.left;
                    else
                            p =p.right;//如果是1,在哈夫曼树中向右找
                    if(p.left==null&&p.right==null)
                            break;
                }   
          
            if( p == null )
                return ERROR;
                return p.value;
        }
       
         //往压缩文件中写编码表信息:字节----字节的权值(出现的次数)
        public void writeEncodingTable( DataOutputStream out ) throws IOException
        {
               
            for( int i = 0; i < BitUtils.DIFF_BYTES; i++ )
            {
                if( theCounts.getCount( i ) > 0 )
                {
                    out.writeByte( i );//写字节
                    out.writeInt( theCounts.getCount( i ) );//写字节出现的次数
                }
            }
            out.writeByte( 0 );
            out.writeInt( 0 );//写一个结束标志
            
        }
       
       //读哈夫曼编码表
        public void readEncodingTable( DataInputStream in ) throws IOException
        {
            for( int i = 0; i < BitUtils.DIFF_BYTES; i++ )
                theCounts.setCount( i, 0 );//初值全部为0
            
            int ch;
            int num;
            
            for( ; ; )
            {
                ch = in.readByte( );//读字节值
                num = in.readInt( );//字节的权值
                if( num == 0 )//遇到结束标志
                    break;
                theCounts.setCount( ch, num );//将读到的结果放入字节计数器
            }
            
            createTree( );//根据字节计数器中的数据,创建哈夫曼树
            charCountSum=charCountSum();//原文件总的字节数
        }
       
        public long charCountSum()//计算原文件总的字节数
        {
                return theCounts.charCountSum();
               
        }
    }
      
    [/code] 最后一个类,完成压缩和解压缩操作
       

        import java.io.*;
    import java.util.Calendar;
    public class Hzip {
       //压缩文件
    public static void compress( String inFile ) throws IOException {
       //读取数据文件
                   
       FileInputStream fis =new FileInputStream(inFile);//要压缩的文件
       CharCounter charCounter=new CharCounter(fis);//字节计数器,统计文件中字节出现的次数
    HuffmanTree tree=new HuffmanTree(charCounter);//根据字节计数器统计的结果创建哈夫曼树,得到根节点
           
       fis.close();
                
           
       String compressedFile = inFile + ".huf";//压缩文件的扩展名为huf      
       OutputStream fout =null;
       fout=new FileOutputStream( compressedFile );//准备要写的压缩文件
            
      DataOutputStream out=new DataOutputStream(fout);
    tree.writeEncodingTable(out);//往压缩文件中写入码表(字节--出现次数)信息,以便解压缩时恢复哈夫曼树
                   
      fis=new FileInputStream(inFile);//原文件
      BitOutputStream hzout = new BitOutputStream(fout );//压缩后的文件
      int ch;
      while( ( ch = fis.read( ) ) != -1 )//从原文件中读一个一个字节地读
      {
      hzout.writeBits( tree.getCode(ch) );//写入这个字节到压缩文件,八位八位地写
      }   
        fis.close( );
         
        hzout.close( );  
        fout.close();
      }
            //解压缩文件
    public static void uncompress( String compressedFile ) throws IOException{
            String outFile;
            String extension;
            
            outFile = compressedFile.substring( 0, compressedFile.length( ) - 4 );
            extension = compressedFile.substring( compressedFile.length( ) - 4 );
            
            if( !extension.equals( ".huf" ) )//先判断要解压文件的扩展名
            {
                System.out.println( "Not a compressed file!" );
                return;
            }
            
          
            InputStream fin = new FileInputStream(compressedFile );//准备读
            DataInputStream in = new DataInputStream( fin );
             
            HuffmanTree tree=new HuffmanTree();
       //先从已压缩文件中读出码表(字节---字节出现的次数)信息,并由此信息创建哈夫曼树,
            //具体代码请参看tree.readEncodingTable(in)方法
            tree.readEncodingTable(in);
            System.out.println("总频数:"+tree.charCountSum);
            //解码,开始解码压缩文件
            BitInputStream hzin = new BitInputStream( in );
            
          OutputStream fout = new FileOutputStream( outFile );//准备输出文件
            int ch;
            long count=0;
             
          //tree.getChar(hzin)方法从BitInputStream流中一位一位的读(然后在树中找节点),
            //直到读到一个哈夫曼编码,返回此哈夫曼编码对应的字节值
            while(( ch =tree.getChar(hzin) ) != -1 )
            {
                    fout.write(ch );//将解压后的字节写入输出文件
                           count++;
                        if(count>=tree.charCountSum)
                                break;
            }
            fin.close();
            hzin.close( );
            fout.close( );
        }
       
        //大家测试吧
        public static void main( String [ ] args ) throws IOException
        {
                String cf="D:\temp\7.bmp";
                long start = System.currentTimeMillis();
                //compress(cf);
                uncompress(cf+".huf");
                long end = System.currentTimeMillis();
                System.out.println("耗时: " + (end-start)+ " 毫秒");
        }
        public static void main2( String [ ] args ) throws IOException
        {
            if( args.length < 2 )
            {
                System.out.println( "Usage: java Hzip -[cu] files" );
                return;
            }
            
            String option = args[ 0 ];
            for( int i = 1; i < args.length; i++ )
            {
                String nextFile = args[ i ];
                if( option.equals( "-c" ) )
                    compress( nextFile );
                else if( option.equals( "-u" ) )
                    uncompress( nextFile );
                else
                {
                    System.out.println( "Usage: java Hzip -[cu] files" );
                    return;
                }
            }
        }
    }
    [/code]
       
    全文完。下载源码:
       

       

       
         
         
          
          

            
          

            
          
         
       

      


    源码下载:http://file.javaxxz.com/2014/11/2/235823906.zip
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-25 16:06 , Processed in 0.377691 second(s), 46 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表