00:00
各位同学,我们来看一下赫夫曼编码的最佳实践,哪一块内容呢?就是我们这儿所说的文件压缩,我们前面讲的是对字符串的压缩,实际上呢?我们在压缩的时候,其实都是压缩成字节,字节数组的,对不对,那也就是说我们也可以对文件来进行这样的一个压缩处理,比如说。现在有一个要求。呃,要求呢,是给你一个图片文件,有一个图片要求对其进行无损压缩,看看压缩的效果怎么样,那么我们来分析一下,如果我们要对文件进行进行压缩,用赫夫曼编码进行压缩,我们的步骤实际上跟我们去把一个字符串压缩成压缩其实大致相同,只是这里面要加入IO的一个操作,是这样子的吧,所以说我们大体是不是读取文件,得到赫夫曼编码,然后完成压缩,再输出这个点,这文件是这样一个流程,好了,那现在呢,我们就来完成这个。
01:08
文件压缩的代码,我们还在原先的这个。呃,Half man code.java文件里面去进行操作,各位同学跟上我的思路,现在呢,我们编写一个方法。编写方法干什么呢?将一个文件进行进行压缩。压缩,因为我们前面讲的对,字符串我们其实都是压缩成压缩成字节的,对不对,压缩成字节数组的,所以说你是二进制的也好,你是文本的文件也好,我都可以进行这个压缩处理,那现在的代码呢,我们来玩一把public。Static void zip。发压缩嘛,那首先呢,你要给我传进来一个文件名。A string。把这个路径给我写清楚,比如说我们就用SRCL原文件,然后呢,我告诉你,待会我把这个文件压缩到哪个位置位置去,比如说dst well,我先呢对这一个方法做一个参数的说明。
02:16
第一个src硕士是你你传入的。传入的希望压缩的文件的全路径。或者叫完整的路径,能理解路径,把这个路径告诉我DSTL呢是我们压缩后,对压缩后将文件,将压缩文件,压缩文件放到哪个哪个目录下。呃,大家知道这意思,好,现在我们就可以开始编写代码了,因为我们整个这个操作呢,会用到IO流,所以说我先创建输出流。输出流,先把输出流这些都用上,待会我要用好吧,创建输出流。
03:02
啊,待会我们再一步步写吧,现在先串一下往这样写啊,一步步来,一步一步来,首先呢,我们这样子创建一个文件的输入流,这个干什么呢?准备读取文件,这个没什么可说的是吧,那就六一个什么呀,Fair。Fire。呃,Input stream对不对,那你读哪一个呢?HRCL,这个大家看能能否理解好,那我就拿到一个文件的枢纽is。那拿到这个流过后呢,大家可以看到我们这相应的这报了一个什么错呢,大家看。啊,他这儿会有异常抛出,那如果有异常抛出的话呢,我们整个先把它踹一下,反正后面呢,我们也要进行这个处理,对不对。所以说我先TRY,然后catch。这次呢,我就简单一点,直接用except,如果拿到这个异常呢,我们把这个异常信息打出来就可以了,好吧,1.getmessage就可以了,然后finally,因为最后呢,我们需要可能需要把这个流给关掉是不是?
04:15
是不是需要把这个流流关掉啊,好,这样子我们待会一步步写吧,拿到这个输入流以后我们干什么呢?我们创建注意听。创建一个。一个和原文件原文件大小一样的一样的这个BAT数组,为什么呀。为什么我要创建这个东西,是不是要读取他的?数据呀。那这个就简单,那么就创建一个,那就BY我快速的写一下。B等于什么呢?又一个bit数组,那这个bit的数组大小是多大呢?好,is.available。这个是不是返回,这个是返回这个文原文件的大小,那这样的我就创建一个跟原文件大小一样的一个bit数组,那拿到这个数组我们该怎么办呢?好,下面我们是不是该读取文件了。
05:17
读取读取文件,那读文件的操作我相信我不用多说,大家都知道要干什么吧,是1.read。把我们B放进去,那这样子的话,我们就把这个src。这里面的内容读到了我们这个。B这个字节数组里面对不对,那读完了过后这个流就没有意义了,就可以把它close掉。对吧。Close掉。呃,当前可以关闭吗?可以关闭,那么这个时候呢,我们可以,诶最后我们可以开close,那这样子我们把这个呢,也定在外边去好吧。创建这个输入文件,输入里呢,我们也定在外边,这样利于我们以后的这个关闭,那这样写,同学们先在这呢,写一个这个空。
06:03
对吧,那这呢,我们就不要了。这样子比较方便,那关闭的动作我们直接放在哪里呢?我们放在这个final里面是不是,但关的时候呢,他又又可能抛出这个异常是不是,那抛出异常我们还得把它进行一个补货。诶,还在进行一个补货,好,那这再踹一下踹一下。出来把它捕获一下,这个没什么大事。好,然后呢,这里面再直接来关闭的时候。这边把这个异常进行一个补货,因为你关闭的关的时候呢,又有可能抛异常还得进行一次补货。这次我们把这个信息再次打出就可以了,Get message。好,这就没没问题,好,那么我们紧接着继续来写你把这个文件。读取到一个字节数组了,下一步该干什么呢?同学们下一步就应该使用。
07:02
使用什么呀,下一步就使用这个赫夫曼。编码进行编码了,那首先我们要拿到赫夫曼编码,要获取到,获取到文件对应的什么赫夫曼编码。表,这个对我们来说应该比较简单,因为前面我们已经有一个方法叫home zip。是这样子的吧,是赫曼进B,然后这边。处理一下我们这边会得到什么呢?诶大家看,把这个币放进去,它整个一下就直接返回了我们的这个。处理过后的赫尔夫曼拜茨。啊,这就直接得到了什么,直接就已经得到了啊。这个应该不是获取到就直接对这个文件进行压缩了,是不是直接直接对这个B数组,B数组,或者叫原文件直接对原文件,原文件压缩。
08:06
对吧,那压缩过呢,我们得到的这个赫夫曼对应的字节数组也就拿到了。好,那这个拿到以后,下面我们该干什么呢?各位同学现在是不是应该创建一个。创建文件的输出流。创建这个输出流准备干什么呢?准备存放,存放这个压缩文件。是这样子的,那重建,嗯,这个输出流呢,我们也写在外边去,那我就开始创建啊叫output。Output什么呢?Output stream OS初始化,给他来一个空。没问题吧,那现在呢,我们在这个地方就可以去处理了,怎么处理六一个fire。Output output。呃,Stream,然后呢,这边DT。
09:04
好,我们得到一个OS,假设这呃这一方我们就不要再去取名了,就上面的OS就可以大家看,跟上我的思路拿到了,那拿这个OSGO下一步该干什么呢?同学们,那么现在就应该创建一个。和文件输出流关联的,注意听object。这个output stream,为什么我要创建这个东西呢?大家一会儿就知道了。那么先把这个写出来,待会我做注释啊,Object。那么这个什么object什么东西呢的,呃,我看看啊,Object的一个output stream。好,这个地方我们写上OS关联上,那既然因为这个流它涉及到一个关闭的问题,因此呢,我在上面去定义这个object output stream的它的一个对象,我们就叫OS吧。
10:03
OS。好,初始化呢,仍然给他一个空,现在我在用OS来接收。我接收到了一个对象输出流,那有些同学刚才想到说老师为什么要做一个对象的输出流呢?大家看我用这个对象输出流的好处是大家有没有发现我可以write一个对象出去。那我把什么?放出去呢。哎,你看我可以直接把我们的这个哈曼的这个bit直接输出去。这时看哈夫曼代茨呢?它是一个宿主。对不对,我可以直接把这个哈曼bits直接以兑现的方式输出去,这样利于我将来的一个恢复,大家以后就会体现到这一点。这里我们。我们以,我们以什么呢?各位同学以对象流的方式写入。
11:03
写,写入这一个赫夫曼的编码。赫夫曼编码。那么目的是干什么呢?是为了是为了以后,以后我们。这个解压的时候,或者叫恢复原文件,这样写啊,恢复原文件时使用。对不对,因为我以对象的流的方式写进去,到时候我以对象流的方式来read一下就完事了,还有一点我一定要告诉大家,我们在。把这个。在进行这个处理的时候,同学们一定要注意。要注意什么问题呢?就是说你一定要把这个赫夫曼编码要写入到。这个压缩文件,否则的话你以后是。你以后就会出什么问题,大家知道吗?你就写不进去了。啊,就挤不进去了,好这地方,这个地方我们是先把啊这里是注意听这里我们先我们是先把什么呢?先把这个。
12:07
这个刚才创建的赫夫曼的拜先放进去的。啊,现在这个编码还没有写,所以说我要在这写一下了,干什么呢,刚才我们把这句话拿到下面来比较好,好。把这个拿到下面来比较好。我们整个都是以对象流的形式来操作的吗?好,这是这个地方是干什么呢?把这个赫就是赫夫曼的赫夫曼。编码后的这个字节,字节数组。哎,字节数组写入,写入这个压缩压缩文件,现在呢,我们还有一个地方就是还要以对象流的方式,把什么呢?把这个后面编码也写进去,因为你不把这个写进去以后,你恢复不了。你恢复不了,所以这方一定要注意,一定要把在说明啊,注意一定要把这个赫夫曼编码写入到压缩文件,你以后,不然的话以后恢复不了了。
13:09
写入追星记得啊。写入。写入。写入压缩文件。压缩文件好,那怎么写进去呢?也分成你的os.right一个。呃,Right,一个object。Right,一个object,那这面我们应该写什么呢?就后面的一个扣子写进去。好,这样也把它写进去了,那写进去以后说白了,我们把这个字节数组写进去了,我们又把赫夫曼编码写进去了,那这个事情基本上就搞定了,搞定过后我们把这个相关的流一起关闭一下,刚才呢,我们仅仅是关闭了这个。呃。这个输入流,现在我们分别把oos也关闭,Close。
14:00
对不对,我们还要把OS也关闭,是这样子的吧。好,这些流呢,我们就统统关闭掉,那关闭掉过后再来看一下我们代码大体是一个什么流程,首先呢,我这里有输入流和输出流,然后我先把这我我先创建了一个输入流的这个对象,然后呢。大家看,我创建了一个跟原文件一样大小的数组,然后读取,读取完了过后呢,我根据这个字节数组获取到了,呃,直接压缩,直接对他压缩,压缩完了过后呢,我拿到了一个赫夫曼的压缩客户的字节数组,那有些说这个哈曼的扣子是怎么得到的呢?因为这个哈曼扣子我们本身是这个对象,我们写的这个类的一个。一个属性,所以说他在在他在进行这个压缩的时候,已经把它初始化过了,还记得吧。大家不相信你,你看就代码里边不要忘了这个事啊,Open你看在这里面,是不是我们在这创,我们在盖着扣子的时候,在这个。
15:07
在在盖的扣子的这个过程中,在这里面大家有没有发现,其实我们已经。在这个操作过程中,是不是已经把这个处理处理过了,你看不停的在处理的时候,其实已经放在了哈夫曼这个扣子里面,这个哈夫曼扣子呢,是我们的一个属性在哪定的,是不是在这定义的,所以说回到刚才这个方法,你你在进行这个。调用调用哈曼这的时候,其实这个哈曼的编码也就拿到了,明白吧,肯定是拿得到的啊,肯定是拿到的好,然后呢,我们在创建一个文件的输出流,然后创建一个跟文件流输出流对应的一个对象,输出流先怎么样呢?先把我们的压缩后的这个数组写进去。然后呢,再把哈弗曼编码写进去,写进去的目的是为了以后进行解压。
16:02
因为你没,如果这个哈弗曼编码表丢掉了以后是肯定恢复不了的,好代码就大致就到这就写结束了,那现在呢,我们来测试一下,同学们,我们来测试一下,还是回到这边来。还是回到这边来,我们来测试。好,现在这些代码呢,我先暂时的给他注销一把,好吧,同学们。呃,注销,呃,我就这样注销。同学们跟上我的思路。现在呢?我们来测试一下压缩文件的代码。往这儿写。测试压缩文件,好的,那在测试之前,我首先需要先写一个原文件的一个路径,好我把这个原文件呢给大家先找一下。我这里呢,准备了一个。备份准备测试的一个BMP文件,我们打开看一下,这个文件呢,是一张图啊,画了一个什么呢?画了一个太阳,很简单很简单,我把这个。
17:03
我把这个文件呢,放在D盘。好,叫SRCBP,好的,我在这写一个路径。这样写,呃,这样也可以对吧,我们路径这样写,然后呢是src.bmp。好的,那这个写完了以后,我们再写一个将来输出的一个位置,比如说de。Dst file,那么我们准备把它放在哪里呢?就放在D盘,我们叫做Zp.B呃,叫src啊DD st.ZP好吧,后缀名咱们就叫zip。写完了过后,我们就调用刚才我们写的那个方法叫Z什么呀范,然后把src地传进去。好,搞定了以后呢,我们提示一句话叫做压缩文件,成功压缩文件。文件,OK。好,那现在呢,我们看一下在这个压缩过程中有没有很多提示信息,我先把它关一下。
18:04
因为我在原先做测试的时候呢,可能有很多输出信息,我先把它关一下,因为这个文件现在就比较大了啊。好,我先运行一下吧,如果有什么输出,我把它。呃,关闭一下就可以了,来运行一把。先看一下D盘下面有没有src。D盘现在是有的,各位同学有的好,各位我运行一下。好的。压缩文件一下就OK了,压缩文件一下就OK了,那打开我们这边看看有没有这个压缩文件呢?好,各位同学,我们看到有个zip啊,有个det,各位这个时候你千万不要尝试着用你7ZP去解压,你解压不不了,他会报告你无法解压,这个原因是为什么?因为你现在用的是7ZP的这个解压的方式去减人,他根本就不识别。说白了它无法识别你,因为你是用你的方式来进行这个压缩的,对吧,所以说你要把这个文件解压,你得自己写解压方法才行,因为这是你自己的算法。
19:08
那么我们看一下,原先是900,呃,900。呃,598现在是。76K,你看这个还是压缩的比较厉害的,当然当然这个也是跟我们这个文件有关系,因为我们这个文件呢,它的像素相对是比较少的,你看我们这个像素画了一个什么玩意儿,其实说白了,这里面很多点都是重复的嘛,因为白没有没有那个没有画线的,那那些点都是重复的,所以压缩率会比较高,那如果你这个图片线条图片很多,那压缩率那就不不会有这么高了,对不对,因为我这个图片它比较简洁,很多的是那个空空白点。好,这点大家注意一下,好嗯,通过这一段代码呢,我们至少可以看到,的确压缩文件是成功了,我们再看看这个代码啊,这个代码就是这样子的,并不是很难,并不是很难,好那关于文件的压缩,它的思路和它的实现方式呢,就给大家先讲到这儿,一会一会呢,我们讲它的文件的解压操作。
我来说两句