之前看到一篇文章,博主给出了压缩文件:https://blog.csdn.net/bluesky_usc/article/details/54185106
在这基础上,添加了对文件进行了解压的方法:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Queue;
import java.util.*;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.LinkedList;
public class Main {
public static void main(String[] args) throws Exception {
//创建压缩对象
Compress compress = new Compress();
//统计文件中0-255出现的次数
compress.countTimes("F:\\test.txt");
//构造哈夫曼树,并得到根节点
HuffmNode root=compress.createTree();
//得到哈夫曼编码
compress.getHuffmCode(root, "");
//压缩文件
compress.compress("F:\\test.txt",
"F:\\test.zip");
compress.Decode("F:\\test.zip" , root); //解压
System.out.println(Compress.breath(root));
}
}
/****/
class HuffmNode {
//数据域
private int data;
//索引
private int index;
//左子节点
private HuffmNode left;
//右子节点
private HuffmNode right;
//哈夫曼节点的构造函数
public HuffmNode(int data,int index){
this.data=data;
this.index=index;
}
//私有属性的封装
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
public HuffmNode getLeft() {
return left;
}
public void setLeft(HuffmNode left) {
this.left = left;
}
public HuffmNode getRight() {
return right;
}
public void setRight(HuffmNode right) {
this.right = right;
}
public String toString() {
// TODO Auto-generated method stub
int num = 0;
if(index != -1)
return "data:" + ((char)this.getIndex()+"") + ",weight:" + this.getData() + "; ";
return "data:" + ((char)this.getIndex()+"") + ",weight:" + this.getData()+ "; ";
}
}
class Compress {
public static int [] times = new int[256];
public String [] HuffmCodes=new String[256];
public LinkedList<HuffmNode> list = new LinkedList<HuffmNode>();
//统计次数
//初始化
public Compress(){
for (int i = 0; i < HuffmCodes.length; i++) {
HuffmCodes[i]="";
}
}
public void countTimes(String path) throws Exception{
//构造文件输入流
FileInputStream fis = new FileInputStream(path);
//读取文件
int value=fis.read();
while(value!=-1){
times[value]++;
value=fis.read();
}
//关闭流
fis.close();
}
//构造哈夫曼树
public HuffmNode createTree(){
//将次数作为权值构造森林
for (int i = 0; i < times.length; i++) {
if(times[i]!=0){
HuffmNode node = new HuffmNode(times[i],i);
//将构造好的节点加入到容器中的正确位置
list.add(getIndex(node), node);
}
}
//将森林(容器中的各个节点)构造成哈夫曼树
while(list.size()>1) {
//获取容器中第一个元素(权值最小的节点)
HuffmNode firstNode =list.removeFirst();
//获取中新的第一个元素,原来的第一个元素已经被移除了(权值次小的节点)
HuffmNode secondNode =list.removeFirst();
//将权值最小的两个节点构造成父节点
HuffmNode fatherNode =
new HuffmNode(firstNode.getData()+secondNode.getData(),-1);
fatherNode.setLeft(firstNode);
fatherNode.setRight(secondNode);
//父节点加入到容器中的正确位置
list.add(getIndex(fatherNode),fatherNode);
}
//返回整颗树的根节点
return list.getFirst();
}
//利用前序遍历获取编码表
public void getHuffmCode(HuffmNode root,String code){
//往左走,哈夫曼编码加0
if(root.getLeft()!=null){
getHuffmCode(root.getLeft(),code+"0");
}
//往右走,哈夫曼编码加1
if(root.getRight()!=null){
getHuffmCode(root.getRight(),code+"1");
}
//如果是叶子节点,返回该叶子节点的哈夫曼编码
if(root.getLeft()==null && root.getRight()==null){
// System.out.println(root.getIndex()+"的编码为:"+code);
HuffmCodes[root.getIndex()]=code;
}
}
//压缩文件
public void compress(String path,String destpath) throws Exception{
//构建文件输出流
FileOutputStream fos = new FileOutputStream(destpath);
FileInputStream fis = new FileInputStream(path);
/**===============将数据写入到文件中================*/
//读文件,并将对应的哈夫曼编码串接成字符串
int value=fis.read();
String str = "";
while(value!=-1){
str+=HuffmCodes[value];
// System.out.println((char)value+":"+str);
value=fis.read();
}
System.out.println(str);
fis.close();
String s="";
while(str.length()>=8){
s=str.substring(0, 8);
int b=changeStringToInt(s);
// System.out.println(c);
fos.write(b);
fos.flush();
str=str.substring(8);
}
int last1=8-str.length();
for (int i = 0; i <last1; i++) {
str+="0";
}
s=str.substring(0, 8);
// System.out.println(s);
int d=changeStringToInt(s);
fos.write(d);
// 补0
fos.write(last1);
fos.flush();
fos.close();
}
//解压缩
public void Decode(String path ,HuffmNode root) throws Exception {
FileInputStream fis = new FileInputStream(path);
int value=fis.read();
int last_num = 0;
String str = "";
String last_str = "";
String b = new String("");
while(value!=-1){
Integer a = new Integer(value);
last_str = str;
str += addZeroForNum(Integer.toBinaryString(a),8);
last_num = value;
// System.out.println((char)value+":"+str);
value=fis.read();
}
str = last_str;
str = str.substring(0,str.length() - last_num);
System.out.println(str);
int num = 0;
int a = (int)(str.charAt(num)-48);
HuffmNode node = null,last_node;
last_node = root;
String os = "";
while(str.length() > 0){
while(true) {
if ((int) (str.charAt(num) - 48) == 0) {
node = last_node.getLeft();
if(node == null){ break;}
}
if ((int) (str.charAt(num) - 48) == 1) {
node = last_node.getRight();
if(node == null){ break;}
}
last_node = node;
num++;
if(num > str.length() - 1)
break;
}
os += ((char)last_node.getIndex() + "");
str = str.substring(num);
num = 0;
last_node = root;
}
System.out.println(os);
}
public static String addZeroForNum(String str,int strLength) {
int strLen =str.length();
if (strLen <strLength) {
while (strLen< strLength) {
StringBuffer sb = new StringBuffer();
sb.append("0").append(str);//左补0
// sb.append(str).append("0");//右补0
str= sb.toString();
strLen= str.length();
}
}
return str;
}
//插入元素位置的索引
public int getIndex(HuffmNode node) {
for (int i = 0; i < list.size(); i++) {
if(node.getData()<=list.get(i).getData()){
return i;
}
}
return list.size();
}
//将字符串转换成整数
public int changeStringToInt(String s){
int v1=(s.charAt(0)-48)*128;
int v2=(s.charAt(1)-48)*64;
int v3=(s.charAt(2)-48)*32;
int v4=(s.charAt(3)-48)*16;
int v5=(s.charAt(4)-48)*8;
int v6=(s.charAt(5)-48)*4;
int v7=(s.charAt(6)-48)*2;
int v8=(s.charAt(7)-48)*1;
return v1+v2+v3+v4+v5+v6+v7+v8;
}
public static <T> List<HuffmNode> breath(HuffmNode root) {
List<HuffmNode> list = new ArrayList<HuffmNode>();
Queue<HuffmNode> queue = new LinkedList<>();
queue.add(root);
while (!queue.isEmpty()) {
HuffmNode pNode = queue.poll();
list.add(pNode);
if (pNode.getLeft() != null) {
queue.add(pNode.getLeft());
}
if (pNode.getRight() != null) {
queue.add(pNode.getRight());
}
}
return list;
}
}