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入门到精通教程
查看: 410|回复: 0

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

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

    [LV.1]初来乍到

    发表于 2014-11-2 23:58:24 | 显示全部楼层 |阅读模式
    继续前文"哈夫曼压缩与解压缩学习笔记(一)"
      

    (3)BitOutputStream.java
        这个类用于写压缩文件,主要方法writeBits(int[] val)用于将某一个字节的哈夫曼编码val写入文件,写的时候是一位一位先写入缓存区(写的顺序是先写缓存区的低位,后到高位),只有满八位时才flush()真正写入,如果没有八位,从下一字节中读入。

    例:上面提到的文件"ASCTASCTAAAAACCTTT",共有18个字符,压缩写时先写第一个字符A,其哈夫曼编码只有一位0,先将0写入缓存区buffer的最低位,buffer=0,再写第二个字符S,一位一位的写,其哈夫曼编码为111,此时缓存区buffer=1110,然后...如下表所示:   
      
       
       

         
       

         
       
      







    字符写入次序    哈夫曼编码                缓冲区buffer的二进制表示
    (1)A             0                 0
    (2)S             111               1110
    (3)C             110               0111110
    (4)T             10                0  (当buffer=10111110时,清空缓存写入
                                              out,T的编码10中的1已写入,0仍在缓存中)
    (5)A             0                 00
    (6)S             111               11100
    (7)C             110               01111100(缓存满,这是第二次写入的数据)
    (8)T             10                01
    (9)A             0                 001
    (10)A            0                 0001
    (11)A            0                 00001
    (12)A            0                 000001
    (13)A            0                 0000001(已有七位)
    (14)C            110               01(buffer=10000001缓存满,这是第三次写入的数据)
    (15)C            110               01101
    (16)T            10                0101101(已有七位)
    (17)T            10                0    (buffer=10101101缓存满,这是第四次写入的数据)
    (18)T            10                010  最后写入的数据
    [/code]

    这样向压缩文件写入的字节数据是: 10111110 01111100  10000001 10101101 010




    import java.io.*;
    public class BitOutputStream {
    private OutputStream out;
    private int buffer;//向输出流out中写一位(bit)数据时,先写入此缓存区,只有满八位时才flush()真正写入out
        private int bufferPos;//缓存区是否满的标志
        public BitOutputStream( OutputStream os )
        {
            bufferPos = 0;
            buffer = 0;
            out = os;
        }
       
        public void writeBit( int val ) throws IOException//向缓存区写一位数据val,取0或1
        {
            buffer = setBit(buffer, bufferPos++, val );//将数据写入缓存区
           if( bufferPos == BitUtils.BITS_PER_BYTES )//缓存区满时,清空并写入out文件
                flush( );
        }
       
      public void writeBits(int [] val) throws IOException//将用数组表示的哈夫曼编码val写入文件
        {
            for( int v : val )
                writeBit( v );
        }   
       
        public void flush( ) throws IOException
        {
            if( bufferPos == 0 )
                return;
            // System.out.println(Integer.toBinaryString(buffer));
            out.write( buffer );
            bufferPos = 0;//缓存区标志复位
            buffer = 0;    //缓存区清空
        }
       
        public void close( ) throws IOException//关闭文件时,要将缓存区的数据写入文件一次
        {
            flush( );
            out.close( );
        }
       
        private int setBit( int pack, int pos, int val )//将pack的第pos位的值设置为1
        {
           // System.out.println("pack="+pack+"  pos="+pos+"   val="+val);
          //  System.out.println();
            if( val == 1 )
                pack |= ( val << pos );//将pack的第pos位的值设置为1
            return pack;
        }
        public static void main(String args[]) throws IOException{
              int[] a={0,0};
              int[] b={1,1,0};
              int[] c={1,1,1};
              int[] d={1,0};
              int[] e={0,1,0,0,1};
         BitOutputStream bo=new BitOutputStream(new FileOutputStream("d:\java\1.txt",true));
              bo.writeBits(a);
              bo.writeBits(b);
              bo.writeBits(c);
              bo.writeBits(d);
              bo.writeBits(e);
             bo.close();
        }
       
       
    }
    [/code] (4)BitInputStream.java

         此类用于解压缩,主要方法readBit()从缓存区中读一位数据,缓存区低位数据先读,高位后读,当缓存区的数据读完时,再从in中读一字节放入缓存区,如何解压缩?先要从压缩文件中读出码表(字节---频率)数据,并构建哈夫曼树,然后如下进行。



    例:对于先前写入压缩文件中字节数据:10111110 01111100  10000001 10101101 010,解压过程度是这样的:

    (1)先读取一字节数据10111110,放入缓存buffer中,读出它的最低位数据0,然后遍历哈夫曼树,从根节点往下找左子节点,发现0正好对应节点A;



    (2)再从缓存buffer中读次低位数据1,又从哈夫曼树的根节点开始找叶子节点,1就从右找,0就左找,如果没有到叶子,再从缓存buffer中读

    一位数据1,还没有到叶子节点,再读一位,这样读三位111后,就找到了对应的S,



    (3)再从缓存中一位一位读三次,由110从哈夫曼树中找到C



    (4)这时缓存buffer中只有一位数据1可读了,读完后再从in中读一字节01111100放入缓存,这时缓存又有数据可读了,读它的最低位0,由10从哈夫曼树中找到T,再下一步找到A,S,C,T,A,A,A,A,A,C,C,T,T,T,这样可由字节数据10111110 01111100  10000001 10101101 010 还原文件"ASCTASCTAAAAACCTTT"。




    import java.io.*;
    public class BitInputStream {
        private InputStream in;//文件输入流
        private int buffer;//八位的缓存区,从in读入的一个字节数据先放在这里
        private int bufferPos;//缓存区标志
        public BitInputStream( InputStream is )
        {
            in = is;
            bufferPos = BitUtils.BITS_PER_BYTES;
        }
       
        //从缓存区中读一位数据,缓存区低位数据先读,高位后读,当缓存区的数据读完时,再从in中读一字节放入缓存区
        public int readBit( ) throws IOException
        {
            if ( bufferPos == BitUtils.BITS_PER_BYTES )
            {
                buffer = in.read( );//从输入流中读一个字节
               // System.out.println(Integer.toBinaryString(buffer));
                if( buffer == -1 )
                    return -1;
                bufferPos = 0;
            }
           // System.out.println("buffer="+buffer);
            return getBit( buffer, bufferPos++ );   
        }
       
        public void close( ) throws IOException
        {
            in.close( );
        }
       
        private static int getBit( int pack, int pos )//获取pack的二进制表示中的第pos位上的数值.
        {
            return ( pack & ( 1 << pos ) ) != 0 ? 1 : 0;
        }
       
        public static void main(String args[]) throws IOException{
           FileInputStream is=new FileInputStream("d:\java\1.txt");
           BitInputStream bi=new BitInputStream(is);
           while(true){
             int b=bi.readBit();
             if(b==-1) break;
              System.out.print(b+"  ");
           }
          
       }
       
    }
    [/code]



    末完待续。。。。。。



      
      
       
       

         
       

         
       
      
    复制代码
    回复

    使用道具 举报

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

    本版积分规则

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

    GMT+8, 2025-2-25 16:19 , Processed in 0.302307 second(s), 36 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

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