压缩:
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(); } }
这样就对一个文本文件实现了压缩功能。剩下的解压,无非是根据文件信息,一步一步经行反步骤,解压开来。这种压缩方式在我的测试中发现有一个缺点,当文件末尾是字符时,就正常运行,当文件最后一个是汉字时,最后一个汉字会被改变,所以这一点暂时还没考虑到,留着广大读者去思考吧。呵呵!