package drug.huffmanCode;
import java.io.*;
import java.util.*;
public class HuffmanCode {
public static void main(String[] args) {
String src = "C:\\Users\\Administrator\\Desktop\\冬马和纱.zip";
String target2 = "C:\\Users\\Administrator\\Desktop\\冬马和纱2.png";
unzipFile(src, target2);
System.out.println("解压完成");
}
public static void unzipFile(String src, String target) {
FileInputStream is = null;
FileOutputStream os = null;
ObjectInputStream ois = null;
try {
is = new FileInputStream(src);
ois = new ObjectInputStream(is);
os = new FileOutputStream(target);
byte[] huffmanBytes = (byte[]) ois.readObject();
Map<Byte, String> map = (Map<Byte, String>) ois.readObject();
byte[] decode = decode(map, huffmanBytes);
os.write(decode);
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void zipFile(String src, String target) {
FileInputStream is = null;
FileOutputStream os = null;
ObjectOutputStream oos = null;
try {
is = new FileInputStream(src);
byte[] bytes = new byte[is.available()];
is.read(bytes);
byte[] zipBytes = huffmanZip(bytes);
os = new FileOutputStream(target);
oos = new ObjectOutputStream(os);
oos.writeObject(zipBytes);
oos.writeObject(huffmanMap);
} catch (FileNotFoundException e) {
System.out.println(e.getMessage());
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static byte[] decode(Map<Byte, String> map, byte[] src) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < src.length; i++) {
boolean flag = (i == src.length - 1);
sb.append(byteToBinaryString(!flag, src[i]));
}
Map<String, Byte> map2 = new HashMap<>();
Set<Byte> keys = map.keySet();
for (Byte key : keys) {
map2.put(map.get(key), key);
}
ArrayList<Byte> target = new ArrayList<>();
for (int i = 0; i < sb.length(); ) {
int count = 1;
boolean flag = true;
Byte b = null;
while (flag) {
String key = sb.substring(i, i + count);
b = map2.get(key);
if (b == null) {
count++;
} else {
flag = false;
}
}
target.add(b);
i += count;
}
byte[] bytes = new byte[target.size()];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = target.get(i);
}
return bytes;
}
public static String byteToBinaryString(boolean flag, byte b) {
int tmep = b;
if (flag) {
tmep |= 256;
}
String str = Integer.toBinaryString(tmep);
if (flag) {
return str.substring(str.length() - 8);
} else {
return str;
}
}
public static byte[] huffmanZip(byte[] src) {
List<Node> nodes = getNodes(src);
Node root = creatHuffmanTree(nodes);
Map<Byte, String> map = creatHuffmanCode(root);
byte[] huffmanCodeBytes = getHuffmanCodeBytes(src, map);
return huffmanCodeBytes;
}
public static byte[] getHuffmanCodeBytes(byte[] bytes, Map<Byte, String> map) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(map.get(b));
}
int len;
if (sb.length() % 8 == 0) {
len = sb.length() / 8;
} else {
len = sb.length() / 8 + 1;
}
byte[] huffmanCodeBytes = new byte[len];
String substring;
int index = 0;
for (int i = 0; i < sb.length(); i += 8) {
if (i + 8 > sb.length()) {
substring = sb.substring(i);
} else {
substring = sb.substring(i, i + 8);
}
huffmanCodeBytes[index] = (byte) Integer.parseInt(substring, 2);
index++;
}
return huffmanCodeBytes;
}
static Map<Byte, String> huffmanMap = new HashMap<>();
static StringBuilder codeBuilder = new StringBuilder();
public static void creatHuffmanCode(Node node, String code, StringBuilder stringBuilder) {
StringBuilder stringBuilder1 = new StringBuilder(stringBuilder);
stringBuilder1.append(code);
if (node.data == null) {
creatHuffmanCode(node.left, "0", stringBuilder1);
creatHuffmanCode(node.right, "1", stringBuilder1);
} else {
huffmanMap.put(node.data, stringBuilder1.toString());
}
}
public static Map<Byte, String> creatHuffmanCode(Node root) {
if (root == null) {
return null;
} else {
creatHuffmanCode(root.left, "0", codeBuilder);
creatHuffmanCode(root.right, "1", codeBuilder);
}
return huffmanMap;
}
public static Node creatHuffmanTree(List<Node> nodes) {
while (nodes.size() > 1) {
Collections.sort(nodes);
Node leftNode = nodes.get(0);
Node rightNode = nodes.get(1);
Node parent = new Node(null, leftNode.count + rightNode.count);
parent.left = leftNode;
parent.right = rightNode;
nodes.remove(leftNode);
nodes.remove(rightNode);
nodes.add(parent);
}
return nodes.get(0);
}
private static List<Node> getNodes(byte[] bytes) {
Map<Byte, Integer> map = new HashMap<>();
for (byte b : bytes) {
Integer count = map.get(b);
if (count == null) {
map.put(b, 1);
} else {
map.put(b, count + 1);
}
}
List<Node> nodes = new ArrayList<>();
Set<Byte> keySet = map.keySet();
for (Byte key : keySet) {
Integer count = map.get(key);
nodes.add(new Node(key, count));
}
return nodes;
}
}
class Node implements Comparable<Node> {
Byte data;
Integer count;
Node left;
Node right;
public Node(Byte data, Integer count) {
this.data = data;
this.count = count;
}
@Override
public String toString() {
return "Node{" +
"data=" + data +
", count=" + count +
'}';
}
@Override
public int compareTo(Node o) {
return this.count - o.count;
}
public void preOrder() {
System.out.println(this);
if (this.left != null) {
this.left.preOrder();
}
if (this.right != null) {
this.right.preOrder();
}
}
}