package com.jason.huffman;
import java.io.*;
import java.util.*;
import java.util.zip.ZipOutputStream;
public class HuffmanCodesDemo {
public static void main(String[] args) {
// String str = "iiii loveeee youuuuu";
// byte[] zipArr = FillBox.getLetterAndCal(str);
// byte[] bytess = FillBox.releaseZip(zipArr);
// System.out.println(new String(bytess));
InOutResourse.getInput("C:\\testzip\\9.png","C:\\testzip\\9.zip");
InOutResourse.outputZip("C:\\testzip\\9.zip","C:\\testzip\\90.png");
}
}
class InOutResourse{
//压缩代码
public static void getInput(String resource,String dest) {
FileInputStream fs =null;
FileOutputStream ofs= null;
ObjectOutputStream oos = null;
try {
fs = new FileInputStream(resource);
byte[] bytes = new byte[fs.available()];
fs.read(bytes);
byte[] lAC = FillBox.getLetterAndCal(bytes);
Map<Byte,String> mapss = FillBox.maps;
ofs = new FileOutputStream(dest);
oos = new ObjectOutputStream(ofs);
oos.writeObject(lAC); //压缩后的编码
oos.writeObject(mapss);//编码对照表
} catch (Exception e) {
System.out.println("失败");
e.printStackTrace();
}finally {
try {
oos.close();
ofs.close();
fs.close();
} catch (Exception e) {
System.out.println("失败");
e.printStackTrace();
}
}
}
public static void outputZip(String resource,String dest){
FileInputStream fs =null;
FileOutputStream ofs= null;
ObjectInputStream ois = null;
try {
fs = new FileInputStream(resource);
ois = new ObjectInputStream(fs);
byte[] by=(byte[]) ois.readObject();
Map<Byte,String> mapg = (Map<Byte,String>) ois.readObject();
FillBox.maps = mapg;
byte[] byteg = FillBox.releaseZip(by);
ofs = new FileOutputStream(dest);
ofs.write(byteg);
} catch (Exception e) {
System.out.println("失败");
e.printStackTrace();
}finally {
try {
ofs.close();
ois.close();
fs.close();
} catch (Exception e) {
System.out.println("失败");
e.printStackTrace();
}
}
}
}
class FillBox{
static Map<Byte,String> maps = new HashMap<>();
static int num=0;
//解压
public static byte[] releaseZip(byte[] ziparr){
//1、将ziparr字节数组 转换成 二进制
StringBuilder sb = new StringBuilder();
String s = null;
String s1 = null;
for (int i = 0;i<ziparr.length;i++){
if (ziparr[i] >= 0){
//如果是最后一个字节
if (i == ziparr.length - 1){
s = Integer.toBinaryString(ziparr[i]);
int len = s.length();
//num记录的是最后一个字节实际的位数,不足则在前面补零
if (len < num){
int k = num - len;
int j = 0;
StringBuilder gg = new StringBuilder();
while ( j < k){
gg.append("0");
j++;
}
s = gg + s;
}
}else { //不是最后一个字节
int a;
//保证 a 转成二进制时 一定是八位的
a = ziparr[i] | 256;
s1 = Integer.toBinaryString(a);
s = s1.substring(1);
}
}else{//如果是负数那么一定就是八位
s1 = Integer.toBinaryString(ziparr[i]);
s = s1.substring(s1.length() - 8);
}
sb.append(s);
}
// 利用sb和maps 还原
// 1、先将maps反转,
Map<String,Byte> maps2 = new HashMap<String,Byte>();
for (Map.Entry<Byte,String> entry : maps.entrySet()){
maps2.put(entry.getValue(),entry.getKey());
}
//2、 查表
int count = 0;
int index = 0;
List<Byte> list = new ArrayList<>();
while(count < sb.length()){
int i = 0;
while (count+i<sb.length()){
String key = sb.substring(count,count+i+1);
if (maps2.get(key)!=null){
list.add(maps2.get(key));
count = count+i+1;
break;
}else {
i++;
}
}
}
byte[] by=new byte[list.size()];
for (int i = 0;i<list.size();i++){
by[i] = list.get(i);
}
return by;
}
//该方法是算出字符串中每个字母出现的次数(权重)
public static byte[] getLetterAndCal(byte[] bytes){
List<Letter> list = new ArrayList<>();
Map<Byte,Integer> map = new HashMap<>();
for (byte b : bytes){
Integer integer = map.get(b);
//如果该字母没有出现过,直接加入到map中
if (integer == null){
map.put(b,1);
}else{//反之,把value++
map.put(b,integer+1);
}
}
//遍历map集合,加入到list集合中
for (Map.Entry<Byte,Integer> entry : map.entrySet()){
list.add(new Letter(entry.getKey(),entry.getValue()));
}
//加入到list集合后,就知道了每个结点的字母和权重,这样就可以开始构造一个哈夫曼树了
Letter head = createHuffmanTree(list);
//获取到了编码表,并存在maps域里
huffmanCodeTab(new StringBuilder(),"",head);
byte[] zip = getZip(bytes);
return zip;
}
// 根据原本的字母字节数组 与 每个字母对应的编码,补齐来
public static byte[] getZip(byte[] by){
//获取了字母字节数组的所有编码
StringBuilder stringBuilder = new StringBuilder();
for (byte b : by){
stringBuilder.append(maps.get(b));
}
// System.out.println(stringBuilder);
//以八位(即,八个二进制数字)为一个字节,分成len个字节
int len = 0;
if (stringBuilder.length() % 8 == 0 ){
len = stringBuilder.length() / 8;
}else {
len = stringBuilder.length() / 8 + 1;
}
//新建一个字节数组,用于存放最终的字母字节数组 压缩过后的 字节数组
byte[] huffmanByte = new byte[len];
int index = 0;
for (int i = 0 ; i < stringBuilder.length() ; i=i+8 ){
String substr;
if (i + 8 > stringBuilder.length()){
num = stringBuilder.length() - i;
substr = stringBuilder.substring(i);
}else {
substr = stringBuilder.substring(i, i + 8);
}
byte i1 = (byte)Integer.parseInt(substr, 2);
huffmanByte[index] = i1;
index ++;
}
return huffmanByte;
}
public static Letter createHuffmanTree(List<Letter> list){
while (list.size() > 1){
Collections.sort(list);
Letter letter1 = list.get(0);
Letter letter2 = list.get(1);
Letter root = new Letter(null,letter1.weight+letter2.weight);
root.leftLetter = letter1;
root.rightLetter = letter2;
list.remove(letter1);
list.remove(letter2);
list.add(root);
}
return list.get(0);
}
public static void preorder(Letter letter){
System.out.println(letter);
if (letter.leftLetter != null)
preorder(letter.leftLetter);
if (letter.rightLetter != null)
preorder(letter.rightLetter);
}
public static void huffmanCodeTab(StringBuilder stringBuilder,String code,Letter root){
StringBuilder stringBuilder1 = new StringBuilder(stringBuilder);
stringBuilder1.append(code);
if (root != null){
if (root.letter == null){
huffmanCodeTab(stringBuilder1,"0",root.leftLetter);//左递归
huffmanCodeTab(stringBuilder1,"1",root.rightLetter);
}else {
maps.put(root.letter,stringBuilder1.toString());
}
}
}
}
class Letter implements Comparable<Letter>{
Byte letter;//字母
int weight;//权重
Letter rightLetter;
Letter leftLetter;
public Letter(Byte letter,int weight){
this.letter = letter;
this.weight = weight;
}
@Override
public String toString() {
return "Letter{" + "letter=" + letter + ", weight=" + weight + '}';
}
@Override
public int compareTo(Letter o) {
return this.weight - o.weight;
}
}
利用哈夫曼压缩文件
最新推荐文章于 2023-05-07 14:36:53 发布