解压缩总体思路:(怎么写进去的就要怎么读出来)
1、读取文件头信息:1)字符种类总数;
2)各字符信息:字符ASCII码,补零个数,占用byte数,编码
(在这过程中,需要把读到的编码转换成与码表中相同的编码)
3)文件末尾补零个数。
2、读取文件信息:读取每个字节转换成01串,前面补零成8位,
加到等待匹配的字符串后,与码表中的编码匹配,写入。
读到文件末尾将加上去的0去掉。
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* 实现文件解压缩
* @author 客
*
*/
public class OpenTest {
//文件输入输出流
FileInputStream fis;
FileOutputStream fos;
//被解压缩文件路径
static String path = "src\\lwq\\java\\HuffmanCode0729\\Untitled 2";
//解压缩后的文件路径
static String newPath = "src\\lwq\\java\\HuffmanCode0729\\Untitled 3";
//存储文件头信息--即各个字符信息的数组
HeadInfo[] head;
//文件末尾补零的数
int fileAddZero;
//记录总共有多少个字符
int codeNum;
public static void main(String[] args) throws IOException{
OpenTest opentest = new OpenTest();
//读取文件头信息
opentest.readHead(path);
//读取文件内容并输出
opentest.readFile(path,newPath);
}
/**
* 读取文件头信息,按写入的顺序依次读出:
* 1、字符种类总数,
* 2、字符ASCII码,编码末尾补零数,字符占字节数,编码
* 3、文件末尾补零数
*
* @throws IOException
*/
public void readHead(String path) throws IOException{
fis = new FileInputStream(path);
//读取字符种类总数
codeNum = fis.read();
System.out.println(codeNum);
//实例化记录文件头信息的数组,数组长度为字符种类总数
head = new HeadInfo[codeNum];
System.out.println("ascii\t字节数\t补零数\t编码");
//以字符种类总数作为循环限制条件,读取每个字符的编码细则
for(int i=0;i<codeNum;i++){
//创建文件头信息对象
HeadInfo info = new HeadInfo();
//读取字符ASCII码,给对象设置ASCII码
info.setAscii(fis.read());
System.out.print(info.getAscii()+"\t"+(char)info.getAscii()+" ");
//读取编码末尾补零数,并给对象设置
info.setZeroNum(fis.read());
//读取编码所占字节数,给对象设置
info.setByteNum(fis.read());
System.out.print(info.getByteNum()+"\t");
//读取当前编码的每个字节
for(int j=0;j<info.getByteNum();j++){
int code_int = fis.read();
//读取到的整数转换成String---0,1串,该01串不会以0开头
String code_string = Integer.toBinaryString(code_int);
// System.out.println("s++"+code_string);
int length = code_string.length();
//01串不足8位的在前面补零
if(length%8!=0){
for(int k=0;k<8-length;k++){
code_string = '0'+code_string;
}
}
//给info对象设置编码,含补零,每个字节的前面补零的01串相加
info.setCode(info.getCode()+code_string);
}
//得到完整的补零后的01串,即文件头信息存储的编码
System.out.print(info.getZeroNum()+"\t");
//根据编码末尾补零个数,恢复编码不补零的编码,即码表中存储的编码,
for(int t=0;t<info.getZeroNum();t++){
info.setCode(info.getCode().substring(0, info.getCode().length()-1));
}
System.out.println("去0后 "+info.getCode());
//将info对象添加到数组中
head[i] = info;
}
//读取头信息的最后一个内容:文章末尾的补零的个数
fileAddZero = fis.read();
System.out.println("文件末尾补零"+fileAddZero);
}
/**
* 读取文件内容,写入新文件,完成解压缩
* @throws IOException
*/
public void readFile(String path,String newPath) throws IOException{
fos = new FileOutputStream(newPath);
//等待转换的字符串
String str = "";
//当文件可读信息大于零时
while(fis.available()>0){
//读取一个字节,赋值给整数txt
int txt = fis.read();
//将该整数转换成01串,该字符串不会以0开头
String temp = Integer.toBinaryString(txt);
System.out.println(temp+" nnnn");
//给转换成的01串,前面补零成完整的8位的字符串
int frontAddZero = temp.length()%8;
if(frontAddZero!=0){
for(int i=0;i<8-frontAddZero;i++){
temp = '0'+temp;
}
}
System.out.println(temp+">>>>>>>>>>>>");
//加到等待转换的字符串后,等待转换
str = str+temp;
System.out.println(str+" !!!!等待转换!!!!");
for(int j=0;j<codeNum;j++){
//判断当前等待转换的字符串,是否以码表中的某个编码开头
if(str.startsWith((head[j].getCode()))){
//如果是,写入这个编码对应的字符
System.out.println(str+" ======== "+head[j].getCode());
// System.out.println("qqqq"+i);
System.out.println((char)head[j].getAscii());
fos.write(head[j].getAscii());
//
//将等待转换的字符串去掉已经写入的编码部分
String tran = str;
str = "";
for(int k=head[j].getCode().length();k<tran.length();k++){
str = str+tran.charAt(k);
}
//设置循环从头开始判断现在的str是否以某编码开头
j = -1;
//如果此时已经没有可读的文件信息了
if(fis.available()==0){
//将文件末尾添加的0的个数,在str中删去
String tra = str;
str = "";
for(int t=0;t<tra.length()-fileAddZero;t++){
str = str+tra.charAt(t);
}
//如果删去之后字符串空了,那么跳出循环,文件读取完毕
if(str==""){
break;
}
//如果str不为空,那么继续j=-1的地方循环判断是否以某编码开头
}
}
}//for循环
}//while循环
//确认文件读取完毕
System.out.println(str.length()+" 最后str的长度");
}
}
本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/jisuanjixue/article-33591-3.html
我们闷头建岛
商会会长
苏-30