java赫夫曼编码压缩解压文件代码实现

package drug.huffmanCode;

import java.io.*;
import java.util.*;

/**
 * @author Drug
 * @create 2020-05-06 18:52
 */
public class HuffmanCode {
    public static void main(String[] args) {
//        String src = "C:\\Users\\Administrator\\Desktop\\冬马和纱.png";
//        String target = "C:\\Users\\Administrator\\Desktop\\冬马和纱.zip";
//        zipFile(src, target);
//        System.out.println("压缩完成!");
        String src = "C:\\Users\\Administrator\\Desktop\\冬马和纱.zip";
        String target2 = "C:\\Users\\Administrator\\Desktop\\冬马和纱2.png";
        unzipFile(src, target2);
        System.out.println("解压完成");
//        String content = "i like like like java do you like a java";
////        byte[] contentBytes = content.getBytes();
////        System.out.println("转换前长度是:" + contentBytes.length);
//////        List nodes = getNodes(contentBytes);
//////        Node root = creatHuffmanTree(nodes);
////////        creatHuffmanCode(root, "", codeBuilder);
////////        System.out.println(huffmanMap);
//////        //方法重载
//////        Map map = creatHuffmanCode(root);
//////        System.out.println(map);
//////
//////        byte[] huffmanCodeBytes = getHuffmanCodeBytes(contentBytes, map);
//////        System.out.println(Arrays.toString(huffmanCodeBytes));
////        byte[] huffmanCodeBytes = huffmanZip(contentBytes);
////        System.out.println(Arrays.toString(huffmanCodeBytes) + "  转换后长度是 " + huffmanCodeBytes.length);
////        //解码
////        byte[] bytes = decode(huffmanMap, huffmanCodeBytes);
////        System.out.println(new String(bytes));

    }

    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();
            }

        }
    }

    /**
     * 压缩文件
     *
     * @param src
     * @param target
     */
    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();
            }
        }
    }

    /**
     * 将目标数组转换成原数组
     *
     * @param src
     * @return
     */
    public static byte[] decode(Map<Byte, String> map, byte[] src) {
        StringBuilder sb = new StringBuilder();
        //用来标记是否是最后一个

        //将目标数组转换成字符串
        for (int i = 0; i < src.length; i++) {
            //当src[i]是最后一个时,flag为true
            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;
    }

    /**
     * 将字节转换成二进制字符串
     *
     * @param flag
     * @param b
     * @return
     */
    public static String byteToBinaryString(boolean flag, byte b) {
        //转换成int
        int tmep = b;
        //如果是正数,补高位
        if (flag) {
            tmep |= 256;
        }
        //返回对应二进制补码
        String str = Integer.toBinaryString(tmep);
        if (flag) {
            return str.substring(str.length() - 8);
        } else {
            return str;
        }
    }

    /**
     * 方法封装
     *
     * @param src
     * @return
     */
    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;
    }

    /**
     * 将字节数组按照map转换
     *
     * @param bytes
     * @param map
     */
    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) {
            //长度刚好被8整除
            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();

    /**
     * 生成赫夫曼编码表
     *
     * @param node
     * @param code
     * @param 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;
    }


    /**
     * 创建赫夫曼树
     *
     * @param nodes
     * @return
     */
    public static Node creatHuffmanTree(List<Node> nodes) {
        //当集合中元素大于1个时,合并树
        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);
    }

    /**
     * 获得节点集合
     *
     * @param bytes
     * @return
     */
    private static List<Node> getNodes(byte[] bytes) {
        Map<Byte, Integer> map = new HashMap<>();
        //将byte放入map中
        for (byte b : bytes) {
            Integer count = map.get(b);
            //没有存放过
            if (count == null) {
                map.put(b, 1);
            } else {
                //map中已有数据,更新数据
                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 +
                '}';
    }

    /**
     * 按count从小到大排
     *
     * @param o
     * @return
     */
    @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();
        }
    }
}

你可能感兴趣的:(java算法)