压缩:
1.压缩思路:
1.把文件的字符读出来,记录出现过的字符及其出现的次数。构造相应的结点。
2.把结点组建成一棵哈夫曼树,并获得哈夫曼编码。
3.利用哈夫曼编码,写入头文件和文件内容。
2.读字符,存队列
1.读取文件信息,存放于数组之中,下标作为ask码值
public int[] countChar(String path){
File file = new File(path);//根据文件地址创建文件对象
int[] c = new int[256];
for(int i=0;i<c.length;i++){
c[i]=0;
}
try {
//创建输出流对象
InputStream is = new FileInputStream(file);
//一个一个的读出
while(is.available()>0){
int i = is.read(); //将文件读入到 数组 中
c[i]++;
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return c;
}
2.构建结点,建造树。
Queue q = new Queue();//实例化队列对象
HFMTree tree = new HFMTree();//实力化一个树对象
//用于记录文件中出现过的字符的次数,下标指 ask码值对应的字符
int[] ch = this.countChar(path);
//利用次数数组创建结点对象,加入队列
for(int i=0;i<ch.length;i++){
if(ch[i]!=0){
//如果出现过该字符,则创建结点,加入队列
Node node = new Node(((char)i)+"", ch[i]);
q.add(node);
}
}
tree.creatTree(q); //利用结点构建树
q = tree.ergodic(tree.getRoot(),""); //遍历树,给结点绘制对应的编码,存储于队列之中
3.第三步骤:
1.头文件
1.头文件包括出现字符的编码。
@ 队列长度(int)
@ 文件末尾补零情况
@ 每一个队列元素
@字符
@编码长度
@最后一次补零的个数
@编码的具体信息
这是头文件的内容格式,也就是必要的一些内容,因为文件本身是一个独立的个体,要考虑到之后能够读取出来,所以必须要存入如上戏信息,不然在打开时,因为不知道文件信息,而无法打开。
2.写入头文件
public void compressFile(String path,String newpath){
File file = new File(path); //将地址解析成具体的文件
File newfile = new File(newpath); //将地址解析成具体的文件
try {
//创建输出流对象
InputStream bis = new FileInputStream(file);
BufferedInputStream is = new BufferedInputStream(bis);
//创建输入流对象
OutputStream bos = new FileOutputStream(newfile);
BufferedOutputStream os = new BufferedOutputStream(bos);
/***将队列读入文件***/
os.write(q.size());
//文件最后补零的情况
int addzero = 0,cache = 0;
for(int i=0;i<q.size();i++){
//文件长度 = 字符次数 * 编码长度
cache += q.get(i).getCount()*q.get(i).getSymbol().length();
}
addzero = 8-cache%8; //文件补零的情况
/***写入文件末尾补零情况****/
os.write(addzero);
/****写入编码信息*****/
for(int i=0;i<q.size();i++){
//获取信息
int xchar = q.get(i).getData().charAt(0);
int xsize = q.get(i).getSymbol().length()/8+1;
int xzero = 8-q.get(i).getSymbol().length()%8;
//写入信息
os.write(xchar);//字符
os.write(xsize);//长度
os.write(xzero);//补零个数
//写入编码
String string = q.get(i).getSymbol();
String waitString = ""; //用来缓存的字符串
//写入编码的前几位
for(int j=0;j<xsize-1;j++){
waitString = "";
waitString = string.substring(0, 8);
string = string.substring(8);
int xString = changeString(waitString);
os.write(xString);
}
//写入编码最后一位
for(int j=0;j<xzero;j++){
string += "0";
}
int xString = changeString(string);
os.write(xString);//写入编码内容
}
3.写入文件内容
String writeString = "";
while(is.available()>0){
int i = is.read(); //将文件读出来
for(int j=0;j<q.size();j++){//用循环找到对应的字符编码
boolean bool = false; //需要寻找的字符还未找到
//如果找到了
if(q.get(j).getData().equals((((char)i)+""))){
int x=0;
while(true){
writeString += q.get(j).getSymbol().charAt(x)+"";
x++;
//如果是因为溢出
if(writeString.length()==8){
int xString = changeString(writeString);
os.write(xString); //写入一个字节
writeString = "";
}
//如果是因为数字位数不足
if(x==q.get(j).getSymbol().length()){
bool = true;
break;
}
}
}//如果找到文件
if(bool==true){
break;
}
}
}
//对最后一个经行处理
if(writeString.length()>0){
int x = 8-writeString.length();
for(int i=0;i<x;i++){
writeString += "0";
}
int xString = changeString(writeString);
os.write(xString);
}
os.close();//关闭输出流
is.close();//关闭输入流
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
这样就对一个文本文件实现了压缩功能。剩下的解压,无非是根据文件信息,一步一步经行反步骤,解压开来。这种压缩方式在我的测试中发现有一个缺点,当文件末尾是字符时,就正常运行,当文件最后一个是汉字时,最后一个汉字会被改变,所以这一点暂时还没考虑到,留着广大读者去思考吧。呵呵!