从0开始打造自己的压缩软件(仅文字适配)上——文本的压缩
一、理清步骤首先作为一个程序我们必然是要一个输入的可能是个文本也可能是其他的内容。那么这个输入输出不能是像过去一样在终端中输入所以这里要引入我们的io流——即为我们的输入和输出的具体办法。然后我们要开始对文件进行压缩那么这里根据的要是什么标准呢因为我们输入的文本不同所以我们的编码方式一定要统一才行呀这里我们把每个字符都利用哈夫曼树进行可以编码从而达到压缩的目的。最后我们要做到把这个翻译出来再进行编译并输出就行了。二、着手进行压缩的部分1.读取首先先写一个读入的函数即传统意义上的输入。这里用到io包中的BufferedReader这个类。publicStringBuilderfileDatanewStringBuilder();StringpathE:\\input.txt;FilefnewFile(path);BufferedReaderbrnull;try{brnewBufferedReader(newFileReader(f));Stringline;while((linebr.readLine())!null){fileData.append(line).append(\r\n);}}catch(Exceptione){thrownewRuntimeException(e);}为了避免文件为空这里可以适用try-catch方法对相应的点进行抓取异常。然后可以加上其他的输出语句如果你需要。在这之后可以很轻松地看出来我们已将一个文件中的全部内容以一个Bufferreader 的形式将文件中的全部数据以一个fileData的读取器给取出来了while循环这里我们是将所有的内容以名为line 的字符串形式读取出来了所有的内容并把他们不断地拼接到起来直到我们没有了内容为止。到那时这还不是我们想要的结果因为现在它还是一个对象我们要不断地取出其中的字符并统计他们出现的频率这样才能搞出想要的结果。我待会说明。哈希表介绍联想到前次的哈希表解释不太全面我重新说一下——这里仅介绍相应的功能特点如需要一些更全面的代码获取请看我上次的文章哈希表和其他的小内容它有一点很好的效果就是在每次使用后面对相同的key值时可以不断地更新后面的value部分使得其能够被不断地使用并覆盖前面的value内容。在这里我们可以很好地使用并适配使得其能够作为一个统计器。现在我们就可以很好地 利用这一特性对每个字符进行统计了。HashMapString,IntegerhmnewHashMap();for(inti0;ifileData.length();i){charcfileData.charAt(i);//查找当前map中的是否存在keyif(hm.containsKey(c)){hm.put(c,hm.get(c)1);}else{hm.put(c,1);}}看到了吗我们通过不断地更新相应的value值将每一个char key都赋予了对应的value值体现了其一一对应的相关关系。2.建树接下来我们可以通过哈夫曼树对每个字符建树。不用担心这个新出现的数据结构。哈夫曼树介绍哈夫曼树是这样的对于一个数列来说不断地去取其中最小的两个数在这之后不断地进行对前两个数进行运算并把运算后的值重新放到数列中进行排列而后周而复始不断循环这样我们便可以得到一个将全部的数都变为一个树的全部叶子节点的树。接下来如果有根节点我们便可以轻松地知道每一个叶子节点的值。再接下来若使每一个节点都与其他节点区分开来我们可以从根节点开始给每一个分支进行编码比如将左儿子编码为0将右儿子编码为1重复此步骤直到所有的叶子节点都能拥有一连串的代表自己的编码。回到我们的应用上来这就可以作为一个例子既然我们需要将频率最高的目标标注出来我们就可以使用这个方法将目标进行相应的编码和使用从而出现每一个字符都有一一对应的相关的编码以字符串的方式进行存储该树即为我们将文件翻译成一连串编码的快捷密码本。for循环的另一个写法不过呢我们要先明了:for循环不是千古不变的一种写法forint i0;in;i{};如果语句需要变得简化我们可以这样写:for(i:n){}二者等效。现在我们先建一个树吧别忘了要先写一个TreeNode 的类不然我们没有根。classTreeNode{publicintdata;publicStringcode;publicStringstr;publicTreeNodeleft;publicTreeNoderight;publicTreeNode(){}publicTreeNode(intdata){this.datadata;}publicTreeNode(Stringstr,intdata){this.datadata;this.strstr;}}这样我们就可以在刚才的环境下建上另一个树了。for(Map.EntryString,Integerentry:hm.entrySet()){TreeNodenodenewTreeNode(entry.getKey(),entry.getValue());nodeList.add(node);这里是能够让每个字符都有能让他对应的节点。现在节点和树都有了链接就行了。publicvoidinOrder(){TreeNodecurrroot;StackTreeNodestacknewStack();while(curr!null||!stack.isEmpty()){if(curr!null){stack.push(curr);currcurr.left;}else{TreeNodenodestack.pop();currnode.right;}}}现在每个字符都已经有但是我们仍然要把他们和自己的编码链接起来让每一个字符都有自己的编码。publicvoidorder(TreeNoderoot,Stringcode){if(rootnull)return;if(root.leftnullroot.rightnull){root.codecode;System.out.println(root.str:root.code);h.put(root.str,root.code);}order(root.left,code0);order(root.right,code1);}既然我们已经有了对应的编码现在就更为方便了。要做的不过是把它从01编码压缩进行加密这是要把每八个01字符转换成一个10进制数字相应的笔记本反而会一各个地记录相应的数字对应的字符这样你的文字便会被加密没有密码本是无法看见的。publicvoidchuli(){intn(8-(g.length()%8))%8;intt0;Integerb0;charc;StringfnewString();Stringend;// char zg.charAt(0);// System.out.println(z);System.out.println();for(inti0;in;i){gg0;}//把g补完try{FileOutputStreamfosnewFileOutputStream(E:\\a.txt);ObjectOutputStreamoosnewObjectOutputStream(fos);oos.writeObject(h);oos.flush();for(inti0;ig.length();i){cg.charAt(i);ff(c);t;if(t8){System.out.println(ff);endendf;bInteger.parseInt(f,2);System.out.println(b);t0;f;fos.write(b);fos.flush();}}System.out.println(end);}catch(Exceptione){thrownewRuntimeException(e);}}好了有人可能注意到这里的不够8位的地方我全用的是0补齐这个地方看一下有个印象就好。本篇代码我放在下面了。packageHOLIDAY;importcom.sun.source.tree.Tree;importjava.sql.SQLOutput;importjava.util.*;importjava.io.*;publicclassHfmTree{publicTreeNoderoot;publicStringBuilderfileDatanewStringBuilder();HashMapString,IntegerhmnewHashMap();HashMapString,StringhnewHashMap();ListTreeNodenodeListnewLinkedList();Stringg;publicvoidread(){// String path D:\\IdeaProjects\\Java01\\src\\K\\Begin.java;0StringpathE:\\input.txt;FilefnewFile(path);BufferedReaderbrnull;try{brnewBufferedReader(newFileReader(f));Stringline;while((linebr.readLine())!null){fileData.append(line).append(\r\n);}}catch(Exceptione){thrownewRuntimeException(e);}System.out.println( fileData fileData.toString());//统计字符频率for(inti0;ifileData.length();i){charcfileData.charAt(i);//查找当前map中的是否存在keyif(hm.containsKey(c)){hm.put(c,hm.get(c)1);}else{hm.put(c,1);}}for(Map.EntryString,Integerentry:hm.entrySet()){TreeNodenodenewTreeNode(entry.getKey(),entry.getValue());nodeList.add(node);}//忘了干啥的了这步}publicvoidsort(ListTreeNodenodeList){for(inti0;inodeList.size();i){for(intj0;jnodeList.size()-1;j){if(nodeList.get(j).datanodeList.get(j1).data){TreeNodetempnodeList.get(j);nodeList.set(j,nodeList.get(j1));nodeList.set(j1,temp);}}}}publicvoidcreateTree(ListTreeNodenodeList){while(nodeList.size()1){sort(nodeList);TreeNodeleftnodeList.remove(0);TreeNoderightnodeList.remove(0);TreeNodenodenewTreeNode(left.dataright.data);node.leftleft;node.rightright;nodeList.add(node);}rootnodeList.remove(0);}publicvoidinOrder(){TreeNodecurrroot;StackTreeNodestacknewStack();while(curr!null||!stack.isEmpty()){if(curr!null){stack.push(curr);currcurr.left;}else{TreeNodenodestack.pop();currnode.right;}}}publicvoidorder(TreeNoderoot,Stringcode){if(rootnull)return;if(root.leftnullroot.rightnull){root.codecode;System.out.println(root.str:root.code);h.put(root.str,root.code);}order(root.left,code0);order(root.right,code1);}publicvoidda(){for(inti0;ifileData.length();i){charcfileData.charAt(i);ggh.get(c);}System.out.print(g);}publicvoidchuli(){intn(8-(g.length()%8))%8;intt0;Integerb0;charc;StringfnewString();Stringend;// char zg.charAt(0);// System.out.println(z);System.out.println();for(inti0;in;i){gg0;}//把g补完try{FileOutputStreamfosnewFileOutputStream(E:\\a.txt);ObjectOutputStreamoosnewObjectOutputStream(fos);oos.writeObject(h);oos.flush();for(inti0;ig.length();i){cg.charAt(i);ff(c);t;if(t8){System.out.println(ff);endendf;bInteger.parseInt(f,2);System.out.println(b);t0;f;fos.write(b);fos.flush();}}System.out.println(end);}catch(Exceptione){thrownewRuntimeException(e);}}publicstaticvoidmain(String[]args){HfmTreehfmnewHfmTree();hfm.read();hfm.createTree(hfm.nodeList);hfm.inOrder();hfm.order(hfm.root,);hfm.da();hfm.chuli();}}classTreeNode{publicintdata;publicStringcode;publicStringstr;publicTreeNodeleft;publicTreeNoderight;publicTreeNode(){}publicTreeNode(intdata){this.datadata;}publicTreeNode(Stringstr,intdata){this.datadata;this.strstr;}}//flie input.string