package com.atguigu.huffmancode;
import java.io.*;
import java.util.*;
/**
* @author Peter
* @date 2022/8/28 11:42
* @description Usage
*/
public class HuffmanCode {
static Map<Byte, String> huffmanCodes = new HashMap<Byte, String>();
static StringBuilder stringBuilder = new StringBuilder();
public static void main(String[] args) {
String content = "i like like like java do you like a java";
System.out.println("content = " + content);
byte[] bytes = content.getBytes();
System.out.println("bytes = " + bytes.length);
byte[] huffmanZip = huffmanZip(bytes);
System.out.println("huffmanZip = " + Arrays.toString(huffmanZip));
System.out.println("huffmanZip.length = " + huffmanZip.length);
/**
* 解码
*/
byte[] sourceBytes = decode(huffmanCodes, huffmanZip);
System.out.println("sourceBytes = " + new String(sourceBytes));
/**
* 压缩文件
*/
String srcFile = "d://test-1.bmp";
String dstFile = "d://test-1.zip";
zipFile(srcFile, dstFile);
System.out.println("文件压缩成功");
/**
* 解压文件
* TODO 解压后的文件不能打开
*/
String zipFile = "d://test-1.zip";
String dstFiles = "d://test-2.bmp";
unZipFile(zipFile, dstFiles);
System.out.println("解压完成");
/*
List<Node> nodes = getNodes(bytes);
System.out.println("nodes = " + nodes);
System.out.println("霍夫曼树--前序遍历");
Node huffmanTreeRoot = createHuffmanTree(nodes);
huffmanTreeRoot.preOrder();
//测试生成了对应的霍夫曼编码
getCodes(huffmanTreeRoot);
System.out.println("huffmanCodes = " + huffmanCodes);
byte[] zip = zip(bytes, huffmanCodes);
//zip = [-88, -65, -56, -65, -56, -65, -55, 77, -57, 6, -24, -14, -117, -4, -60, -90, 28]
System.out.println("zip = " + Arrays.toString(zip));
*/
}
/**
* 文件解压
*
* @param zipFile 待解压的文件
* @param dstFile 解压后的文件存储位置
*/
public static void unZipFile(String zipFile, String dstFile) {
InputStream is = null;
ObjectInputStream ois = null;
OutputStream os = null;
try {
is = new FileInputStream(zipFile);
ois = new ObjectInputStream(is);
byte[] huffmanBytes = (byte[]) ois.readObject();
Map<Byte, String> huffmanCodes = (Map<Byte, String>) ois.readObject();
//解码
byte[] decodes = decode(huffmanCodes, huffmanBytes);
//将decodes写入文件
os = new FileOutputStream(dstFile);
os.write(decodes);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
//与打开顺序相反
if (os != null) {
os.close();
}
if (ois != null) {
ois.close();
}
if (is != null) {
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 将一个文件进行压缩
*
* @param srcFile 待压缩的文件路径
* @param dstFile 压缩后的文件存储位置
*/
public static void zipFile(String srcFile, String dstFile) {
FileInputStream fis = null;
OutputStream os = null;
ObjectOutputStream oos = null;
try {
fis = new FileInputStream(srcFile);
//创建一个与原文件大小一样的byte[]
byte[] bytes = new byte[fis.available()];
//读取文件
fis.read(bytes);
//获取文件对应的霍夫曼编码表
byte[] huffmanZipBytes = huffmanZip(bytes);
os = new FileOutputStream(dstFile);
//创建一个与文件输出流关联的ObjectOutputStream
oos = new ObjectOutputStream(os);
//以对象流的方式写入霍夫曼编码
oos.writeObject(huffmanZipBytes);
//这里我们以对象流的方式写入 赫夫曼编码,是为了以后我们恢复源文件时使用
//注意一定要把赫夫曼编码 写入压缩文件
oos.writeObject(huffmanCodes);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (oos != null) {
oos.close();
}
if (os != null) {
os.close();
}
if (fis != null) {
fis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* @param huffmanCodes 霍夫曼编码表map
* @param huffmanBytes 霍夫曼编码得到的字节数组
* @return
*/
private static byte[] decode(Map<Byte, String> huffmanCodes, byte[] huffmanBytes) {
//1.先得到huffmanBytes对应的二进制的字符串
StringBuilder stringBuilder = new StringBuilder();
//将byte数组转成二进制的字符串
for (int i = 0; i < huffmanBytes.length; i++) {
byte b = huffmanBytes[i];
//判读是否最后1个字节
boolean flag = (i == huffmanBytes.length - 1);
stringBuilder.append(byteToBitString(!flag, b));
}
//System.out.println("stringBuilder = " + stringBuilder.toString());
//把字符串按照指定的霍夫曼编码进行解码
Map<String, Byte> map = new HashMap<>();
for (Map.Entry<Byte, String> entry : huffmanCodes.entrySet()) {
map.put(entry.getValue(), entry.getKey());
}
//System.out.println("map = " + map);
//创建集合,存放byte
ArrayList<Byte> list = new ArrayList<>();
for (int i = 0; i < stringBuilder.length(); ) {
int count = 1;
boolean flag = true;
Byte b = null;
while (flag) {
/**
* TODO 解压时StringIndexOutOfBoundsException: String index out of range: 64587
* Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 64587
* at java.lang.AbstractStringBuilder.substring(AbstractStringBuilder.java:933)
* at java.lang.StringBuilder.substring(StringBuilder.java:76)
* at com.atguigu.huffmancode.HuffmanCode.decode(HuffmanCode.java:212)
* at com.atguigu.huffmancode.HuffmanCode.unZipFile(HuffmanCode.java:92)
* at com.atguigu.huffmancode.HuffmanCode.main(HuffmanCode.java:48)
*/
String key = stringBuilder.substring(i, i + count);
b = map.get(key);
if (b == null) {
count++;
} else {
//匹配到
flag = false;
}
}
list.add(b);
//i移动到count位置
i += count;
}
//把list中的数据放到byte[]中
byte[] bytes = new byte[list.size()];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = list.get(i);
}
return bytes;
}
/**
* 将一个byte转换成一个二进制的字符串
*
* @param flag 标志是否需要补高位;如true则需要补高位
* @param b 传入的byte
* @return b对应的二进制字符串(补码返回)
*/
private static String byteToBitString(boolean flag, byte b) {
int temp = b;
//如果是正数,须补高位
//按位
极致人生-010
- 粉丝: 4436
- 资源: 3089
最新资源
- 音乐网站(JSP+SERVLET).rar
- 抢购软件:快速复制信息
- oracle错误代码和信息速查手册chm版最新版本
- MATLAB【逆变器二次调频模型】 微电网分布式电源逆变器DROOP控制二次调频模型,加入二次控制实现二次调频控制,及二次调压控制,程序可实现上图功能,工况有所改变 需要matlab2021A版
- 基于python的网页自动化工具项目全套技术资料100%好用.zip
- Oracle数据库命令速查手册doc版最新版本
- 程序名称:转向设计计算程序 开发平台:基于matlab平台 计算内容:阿克曼转角,转弯半径,转向阻力矩,回正力矩,转向主参数,转向传动比,力矩波动,转向梯形,EPS匹配,HPS匹配,齿轮齿条传动比,循
- 基于二阶自抗扰ADRC的轨迹跟踪控制,对车辆的不确定性和外界干扰具有一定抗干扰性,基于carsim和simulink仿真 跟踪轨迹为双移线,效果良好,有对应复现资料,是学习自抗扰技术快速入门很好的资料
- TianleSoftwareOracle学习手册中文pdf格式最新版本
- MATLAB代码:基于分布式ADMM算法的考虑碳排放交易的电力系统优化调度研究 关键词:分布式调度 ADMM算法 交替方向乘子法 碳排放 最优潮流 仿真平台:MATLAB+CPLEX GUROBI
- Oracle安装配置使用WORD文档doc格式最新版本
- 西门子840D HMI ADVANCED FOR PC 也可用于810D,840DSL中文版 1、软件可安装到台式机或笔记本上,可以连接到机床的NCU进行NC与PLC的数据备份与恢复,备份和恢复的数
- OraclePLSQL简单安装指南WORD文档doc格式最新版本
- 网页数据采集软件项目全套技术资料100%好用.zip
- Oracle高级SQL培训与讲解WORD文档doc格式最新版本
- 超智能体写的人工智能深度学习pdf
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈