当前位置: 首页 > news >正文

Java实现霍夫曼编码对文件解压缩

压缩流程:
1.将文本转换为字节数组,计算字节频率。扫描一个字节,频率+1
2.根据字节频率建立霍夫曼树,用最小堆。每次取最小的两个,加入最小堆中。
3.根据霍夫曼树遍历,左一次为0,右一次为1。为字节数组编新的码。字节数组和码一起生成压缩的
4.输出压缩文件

解压流程:
1.根据霍夫曼树,按压缩的码遍历,0为左遍历,1为右遍历,到叶子了就是新的码,每次都要重头遍历霍夫曼树
2.输出解压文件。

霍夫曼树节点类定义

    private static class HuffmanNode implements Comparable<HuffmanNode> {byte data;int frequency;HuffmanNode left, right;public HuffmanNode(byte data, int frequency) {this.data = data;this.frequency = frequency;}public HuffmanNode(int frequency, HuffmanNode left, HuffmanNode right) {this.frequency = frequency;this.left = left;this.right = right;}public boolean isLeaf() {return left == null && right == null;}@Overridepublic int compareTo(HuffmanNode other) {return this.frequency - other.frequency;}}

压缩代码

    /*** 压缩文件* @param inputFile 输入文件路径* @param outputFile 输出文件路径*/public static void compress(String inputFile, String outputFile) throws IOException {byte [] fileData = readFile(inputFile);int [] frequenct = computeFrequency(fileData);HuffmanNode root = buildHuffmanTree(frequenct);String [] codes = new String[256];generateCodes(root,"",codes);BitOutputStream bitout = new BitOutputStream();for (byte b : fileData){String code = codes[b&0xFF];for (char c :code.toCharArray()){bitout.writeBit( c == '1');}}bitout.close();try(DataOutputStream out = new DataOutputStream(new FileOutputStream(outputFile))){//写入 字节频率for (int i = 0 ; i < 256 ; i ++){out.writeInt(frequenct[i]);}//写入实际位数out.writeInt(bitout.getBitCount());out.write(bitout.toByteArray());}}

读文件

    //读文件public static byte[] readFile(String filePath) throws IOException {try(FileInputStream in = new FileInputStream(filePath);ByteArrayOutputStream out = new ByteArrayOutputStream()){byte [] buffer = new byte[4096];int bytesRead;while( (bytesRead = in.read(buffer)) != -1 ){out.write(buffer,0,bytesRead);}return out.toByteArray();}}

获取字节频率

    //获取字节的频率public static int [] computeFrequency(byte [] fileDate){int [] frequency = new int[256];for (byte b : fileDate){frequency[b&0xFF]++;}return frequency;}

构建霍夫曼树

    //构建霍夫曼树private static HuffmanNode buildHuffmanTree(int[] frequency) {PriorityQueue<HuffmanNode> queue = new PriorityQueue<>();// 创建叶子节点并加入优先队列for (int i = 0; i < 256; i++) {if (frequency[i] > 0) {queue.offer(new HuffmanNode((byte) i, frequency[i]));}}// 处理特殊情况:空文件或只有一个字节的文件if (queue.isEmpty()) {return new HuffmanNode((byte) 0, 0);}if (queue.size() == 1) {HuffmanNode node = queue.poll();return new HuffmanNode(node.frequency, node, null);}// 合并节点直到只剩一个根节点while (queue.size() > 1) {HuffmanNode left = queue.poll();HuffmanNode right = queue.poll();HuffmanNode parent = new HuffmanNode(left.frequency + right.frequency, left, right);queue.offer(parent);}return queue.poll();}

生成霍夫曼编码

    //生成霍夫曼编码public static void generateCodes(HuffmanNode node,String code,String [] codes){if(node.isLeaf()){codes[node.data & 0xFF] = code;}else{generateCodes(node.left,code +"0",codes);generateCodes(node.right,code +"1",codes);}}

按位读写流

   private static class BitOutputStream {private ByteArrayOutputStream out = new ByteArrayOutputStream();private int currentByte;private int bitCount;private int totalBits;public void writeBit(boolean bit) {currentByte = (currentByte << 1) | (bit ? 1 : 0);bitCount++;totalBits++;if (bitCount == 8) {out.write(currentByte);currentByte = 0;bitCount = 0;}}public void close() {// 填充剩余的位if (bitCount > 0) {currentByte <<= (8 - bitCount);out.write(currentByte);}}public byte[] toByteArray() {return out.toByteArray();}public int getBitCount() {return totalBits;}}
    //位输入流 - 用于按位读取数据private static class BitInputStream {private byte[] data;private int currentByteIndex;private int currentBitIndex;private int totalBits;private int bitsRead;public BitInputStream(byte[] data, int totalBits) {this.data = data;this.totalBits = totalBits;}public boolean readBit() {if (bitsRead >= totalBits) {return false;}if (currentBitIndex == 8) {currentByteIndex++;currentBitIndex = 0;}boolean bit = (data[currentByteIndex] & (1 << (7 - currentBitIndex))) != 0;currentBitIndex++;bitsRead++;return bit;}}

解压

    /*** 解压文件* @param inputFile 输入文件路径* @param outputFile 输出文件路径*/public static void decompress(String inputFile, String outputFile) throws IOException {try (DataInputStream in = new DataInputStream(new FileInputStream(inputFile))) {// 读取频率表int[] frequency = new int[256];for (int i = 0; i < 256; i++) {frequency[i] = in.readInt();}// 重建霍夫曼树HuffmanNode root = buildHuffmanTree(frequency);// 读取压缩数据int bitCount = in.readInt();byte[] compressedData = new byte[in.available()];in.readFully(compressedData);//  解码数据ByteArrayOutputStream output = new ByteArrayOutputStream();HuffmanNode current = root;BitInputStream bitIn = new BitInputStream(compressedData, bitCount);for (int i = 0; i < bitCount; i++) {boolean bit = bitIn.readBit();current = bit ? current.right : current.left;if (current.isLeaf()) {output.write(current.data);current = root;}}// 写入解压文件try (FileOutputStream out = new FileOutputStream(outputFile)) {out.write(output.toByteArray());}}}

测试

    public static void main(String[] args) {try {String inputFile = "E:\\DemoTest\\test.txt";String compressedFile = "E:\\DemoTest\\test_compressed.huff";String decompressedFile = "E:\\DemoTest\\test_decompressed.txt";// 压缩long startTime = System.currentTimeMillis();compress(inputFile, compressedFile);long compressTime = System.currentTimeMillis() - startTime;// 解压startTime = System.currentTimeMillis();decompress(compressedFile, decompressedFile);long decompressTime = System.currentTimeMillis() - startTime;// 计算压缩率File original = new File(inputFile);File compressed = new File(compressedFile);double ratio = (1 - (double) compressed.length() / original.length()) * 100;System.out.println("压缩完成!");System.out.println("压缩时间: " + compressTime + "ms");System.out.println("解压时间: " + decompressTime + "ms");System.out.println("压缩率: " + String.format("%.2f", ratio) + "%");} catch (IOException e) {e.printStackTrace();}}

测试结果

压缩完成!
压缩时间: 1388ms
解压时间: 1563ms
压缩率: 29.73%

在这里插入图片描述
在这里插入图片描述

http://www.dtcms.com/a/419121.html

相关文章:

  • Kubernetes 中 ETCD 数据备份与恢复完整指南
  • Go 语言中指针介绍
  • 权重的网站建设网站有哪些内容
  • vxe-grid @edit-closed方法不被执行或者叫不触发
  • CF Yamakasi (前缀和+双指针)
  • 机器学习-第三章 线性模型
  • 新手想做网站赚钱app制作开发公司怎么收费
  • 现代Web存储技术(二):存储容量规划与传统方案对比
  • PyTorch实战(8)——图像描述生成
  • App Store 上架完整流程解析,iOS 应用发布步骤、ipa 文件上传工具、TestFlight 测试与苹果审核经验
  • stm32和Zynq的中断抢占机制
  • iOS App 混淆实战,在源码不可用情况下的成品加固与测试流程
  • Python爬虫技术:招标信息抓取与关键词过滤 (1)
  • 莞城网站推广wordpress图片并列排
  • 塘厦仿做网站wordpress和jwplayer
  • 嵌入式 - 内核驱动3 - class/device | misc | ioctl |device/driver
  • Matlab通过GUI实现点云的双边(Bilateral)滤波(附最简版)
  • 4-5〔O҉S҉C҉P҉ ◈ 研记〕❘ WEB应用攻击▸远程文件包含漏洞
  • 怎么在淘宝上做网站中交建设集团网站
  • 在线查看网站源码中国最新新闻
  • 轴状态读取(运动控制系列)
  • quic的拥塞控制
  • 【模型系列】Human-in-the-Loop
  • AI项目问题总结大全
  • 【linux内核驱动day03】
  • Accelerate基本使用
  • Day75 基本情报技术者 单词表10 ネットワーク応用
  • 企业网站美化做常州美食网站首页的背景图
  • 网站建设设计的流程wordpress的搭建教程 pdf
  • 页网站腾讯云学生机做网站