运用哈费曼压缩和解压文件

第一点:文件是由字节组成,一个字节的长度为8位,所以最多存在256位字节


第二点:由于文件中会含有一个或多个相同的字节,所以我们可以将相同的字节使用更加精简的方式表示;

如:假设压缩一个文件,文件中的字节为aaabbc,

第一步,首先统计每个字符出现的次数

public class CountChar {

int[] allChar = new int[256]; // 保存所有字符的个数
File file = new File("man.txt");  //创建文件管道
FileInputStream is = null;    //输入流
BufferedInputStream bs = null;  //给输入流包装一个缓冲流
try {   
is = new FileInputStream(file);
bs = new BufferedInputStream(is);
int read = bs.read();  //读取文件
while (read != -1) {
allChar[read] = allChar[read] + 1;
System.out.println((char) read);
read = bs.read();
}
// Arrays为操作数组的工具类,toString为返回数组的表现形式
System.out.println(Arrays.toString(allChar));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is.close();
bs.close();
} catch (IOException e) {
e.printStackTrace();
}

}
}



第二步:创建哈弗曼树

//创建哈费曼树
public class CreateTree {
HfmTree node;
int[] allChar = getAllChar();
// 创建优先级队列(PriorityBlockingQueue为优先级)
PriorityBlockingQueue<HfmTree> pq = new PriorityBlockingQueue<HfmTree>();
for (int i = 0; i < allChar.length; i++) {
if (allChar[i] == 0) {
continue;
}
HfmTree node = new HfmTree(allChar[i], i);
pq.add(node);
System.out.println(allChar[i]);
}


private static int[] getAllChar() {
int[] allchar = new int[256];
allchar[97] = 3;
allchar[98] = 2;
allchar[99] = 1;
return allchar;
}
}


第三步:生成哈弗曼编码

public class CreateHfmDict {
String[] allCode = new String[256];
public static void main(String[] args) {
CreateHfmDict cd = new CreateHfmDict();
HfmTree root = createRoot();


for (int i = 0; i < cd.allCode.length; i++) {
cd.allCode[i] = "";
}
cd.createHfmDict(root, "");
for (int i = 0; i < cd.allCode.length; i++) {
if (cd.allCode[i].equals("")) {
continue;
}
System.out.println(cd.allCode[i] + "--" + i);
}
}
private void createHfmDict(HfmTree node, String code) {
if (node.getLeftNode() == null && node.getRightNode() == null) {
Integer data = node.getData();
allCode[data] = code;
}
if (node.getLeftNode() != null) {
createHfmDict(node.getLeftNode(), code + "0");
}
if (node.getRightNode() != null) {
createHfmDict(node.getRightNode(), code + "1");
}

}

private static HfmTree createRoot() {
HfmTree nodeA = new HfmTree(3, 97);  //生成a的哈费曼编码
HfmTree nodeB = new HfmTree(2, 98);  //生成b的哈费曼编码
HfmTree nodeC = new HfmTree(1, 99);  //生成c的哈费曼编码


HfmTree nodebc = new HfmTree(3, null);
nodebc.setLeftNode(nodeB);
nodebc.setRightNode(nodeC);


HfmTree nodeZ = new HfmTree(6, null);
nodeZ.setLeftNode(nodeA);
nodeZ.setRightNode(nodebc);


return nodeZ;
}

}

第四步:向文件写入每个哈弗曼码的长度

public class WriteHfmCodeLength {
public static void main(String[] args) {
File file = new File("File.txt");
FileOutputStream fs = null;
BufferedOutputStream bs = null;
try {
fs = new FileOutputStream(file);
bs = new BufferedOutputStream(fs);


String allCode[] = getAllCode();
for (int i = 0; i < allCode.length; i++) {
// 获取第i个哈弗曼编码的长度
int l = allCode[i].length();
// 将长度写入到文件中
bs.write(l);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fs.flush();
bs.flush();
fs.close();
bs.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static String[] getAllCode() {
String allCode[] = new String[256];
for (int i = 0; i < allCode.length; i++) {
if (i == 97) {
allCode[i] = "0"; // a的哈费曼编码
} else if (i == 98) {
allCode[i] = "10"; // b的哈弗曼编码
} else if (i == 99) {
allCode[i] = "11"; // c的哈弗曼编码
} else {
allCode[i] = "";
}
}
return allCode;
}

第五步:生成所有hfm码的二进制字符串,追加到变量中

public class AppendHfmCodeData {
String[] allCode = getAllCode();
String string = Arrays.toString(allCode);
string = string.replace("[", ""); // 表示将“...”转换成“...”(如此处表示将“【”装换成“”空值)
string = string.replace(" ", "");
string = string.replace(",", "");
string = string.replace("]", "");
System.out.println(string);
}
private static String[] getAllCode() {
String[] allCode = new String[256];
for (int i = 0; i < allCode.length; i++) {
if (i == 97) {
// a的哈弗曼编码
allCode[i] = "0";
} else if (i == 98) {
// b的哈弗曼编码
allCode[i] = "10";
} else if (i == 99) {
// c的哈弗曼编码
allCode[i] = "11";
} else {
allCode[i] = "";
}
}
return allCode;
}


第六步:读取文件,对文件中的每个字节根据hfm码进行转换,生成二进制字符串,追加到变量中

public class AppendFileDataByHfmCode {
// 000101011  (上一步获得的二进制)
StringBuffer fileData = new StringBuffer();
// 手动构造了所有的哈弗曼编码
String[] allCode = getAllCode();
// 输入流
FileInputStream fis = new FileInputStream("man.txt");
// 缓冲流
BufferedInputStream bos = new BufferedInputStream(fis);
int read;
while ((read = bos.read()) != -1) {
// 如果读到a,read=97,获取allCode[97]
String hfmCode = allCode[read];
fileData.append(hfmCode);
}
System.out.println(fileData);
bos.close();
}
private static String[] getAllCode() {
String[] allCode = new String[256];
for (int i = 0; i < allCode.length; i++) {
if (i == 97) {
// a的哈弗曼编码
allCode[i] = "0";
} else if (i == 98) {
// b的哈弗曼编码
allCode[i] = "10";
} else if (i == 99) {
// c的哈弗曼编码
allCode[i] = "11";
} else {
allCode[i] = "";
}
}
return allCode;
}
}

第七步:补0操作(即将二进制中缺少8位的前面补上0,使其具有8位字节)

public class AppendZero {
public static void main(String[] args) {
StringBuffer hfmData = new StringBuffer("01011000101011");// 将此数据补零
// 记录补充了多少个0
int count = 0;
// 补0
while (hfmData.length() % 8 != 0) {
hfmData.append("0");
count++;
}
// 01011000101011 00 00000010
// 将十进制数字转换为二进制字符串
String countStr = Integer.toBinaryString(count);
while (countStr.length() < 8) {
countStr = "0" + countStr;
}
hfmData.append(countStr);
System.out.println(hfmData + "==" + hfmData.length());
}
}


最后一步:压缩文件,即向另一个文件写入数组中的二进制数,就可完成压缩

public class WriteData {
File file = new File("File.txt");
// 输出流
FileOutputStream fos = new FileOutputStream(file, true);
// 缓冲流
BufferedOutputStream bos = new BufferedOutputStream(fos);
StringBuffer data = new StringBuffer("010110001010110000000010");
while (data.length() != 0) {
// 截取StringBuffer [ )
String substring = data.substring(0, 8);
System.out.println(substring);
int parseInt = Integer.parseInt(substring, 2);
bos.write(parseInt);
// 删除StringBuffer [ )
data.delete(0, 8);
}
bos.flush();
bos.close();
}
}

之后再main方法中一一调用这些方法即可完成文件的压缩;但此处压缩是为固定形态。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值