文件压缩和解压

来源:互联网 发布:手机淘宝怎么取消退款? 编辑:程序博客网 时间:2024/04/25 07:26

今天刚学完文件的压缩和解压,在老师的帮助下完成了这个小程序,感觉很有干劲,很充实,不想以前的暑假,不是在看小说就看视频,虽然一时感觉很愉悦,然而玩了以后就很无聊,觉得无所事事,下面是文件压缩和解压代码和大家分享一下。

  文件压缩最重要的数据结构:哈夫曼二叉树(最优二叉树)

//构造哈夫曼二叉树结点:

     package hmfTree;
   public class HfmTreeNode implements Comparable<HfmTreeNode> {
    private HfmTreeNode leftNode;
    private HfmTreeNode rightNode;
    private Integer times;
    private Integer data;
public HfmTreeNode getLeftNode() {
return leftNode;
}
public void setLeftNode(HfmTreeNode leftNode) {
this.leftNode = leftNode;
}
public HfmTreeNode getRightNode() {
return rightNode;
}
public void setRightNode(HfmTreeNode rightNode) {
this.rightNode = rightNode;
}
public Integer getTimes() {
return times;
}

public void setTimes(Integer times) {
this.times = times;
}
//构造函数
public HfmTreeNode(Integer times , Integer data){
this.times=times;
this.data=data;
}
public Integer getData() {
return data;
}
public void setData(Integer data) {
this.data = data;
}
public int compareTo(HfmTreeNode o)
{
return times.compareTo(o.times);
}


// public String toString()
// {
// return "[" + times + "]";
// }
}



package hmfTree;
/*
 * 压缩文件
 * 
 */
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.PriorityQueue;


public class test {
//保存所有哈夫曼编码
String [] allCode=new String[256];

//保存所有字符个数
int[] allChar= new int[256];
PriorityQueue <HfmTreeNode> HfmList=new PriorityQueue<HfmTreeNode>();

    public static void main(String[] args){
   
    test t=new test();
    //压缩过程
    //获取所有字符的个数
    t.CountChar("t.txt");
    //构造Hfm树
          HfmTreeNode root=t.CreateTree();
        //生成所有字符的哈夫曼编码
          t.CreateHfmDict(root,"");
          //打印
          for(int i=0;i<t.allCode.length;i++){
         System.out.println(t.allCode[i]+"------"+i);
          }
          //写哈夫曼编码长度
           t.WriteHfmCodeLength("t1.txt");
           //获取哈夫曼编码
           StringBuffer f=new StringBuffer("");
           StringBuffer HfmCodeData=f.append(t.AppendHfmCodeData());
      //获取文件数据
           StringBuffer fileData= t.AppendFileDataByHfmCode("t.txt");
           //哈夫曼编码加文件数据
           StringBuffer HfmData=HfmCodeData.append(fileData);
        System.out.println(HfmData);
        //获取补零后的数据
           StringBuffer HfmData1=t.AppendZero(HfmData);
           System.out.println(HfmData1+"-----"+HfmData1.length());
          //把压缩后的数据写入文件
          t.WriteData("t1.txt", HfmData1);
          
        
          
    }
    //获取所有字符的个数
    public void CountChar(String fileName){
    //初始化allCode数组
    for(int i=0;i<allCode.length;i++){
    allCode[i]="";
    }
   
    
    try{
    File file=new File(fileName);
        //创建文件输出流
         FileInputStream fis=new FileInputStream(file);
         //包装成缓冲文件
         BufferedInputStream bis=new BufferedInputStream(fis);
        int i;


      while ((i = bis.read()) != -1)
       {
       allChar[i]++;
       }
      
        //Arrays为操作数组的类
      System.out.println(Arrays.toString(allChar));
        
        //关闭输入流
         bis.close();
       
           }catch(IOException e){
        e.printStackTrace();
    System.out.println("此文件不存在!!!");
        }
     
       
    }
      //构造Hfm树
        public HfmTreeNode CreateTree(){
   
    for(int i=0;i<256;i++){
    if(allChar[i]!=0){
    //加入Hfm树的子结点
    HfmTreeNode node=new HfmTreeNode(allChar[i],i);
    HfmList.add(node);
    }
    }
    while(HfmList.size()!=1){
    HfmTreeNode leftNode=HfmList.poll();
    HfmTreeNode rightNode =HfmList.poll();
    //得到新的父节点
    Integer newtimes=leftNode.getTimes()+rightNode.getTimes();
    HfmTreeNode newnode=new HfmTreeNode(newtimes,null);
    HfmList.add(newnode);
    //设置父节点的左右子结点
    newnode.setLeftNode(leftNode);
    newnode.setRightNode(rightNode);
    }
            HfmTreeNode root=HfmList.peek();   //哈夫曼树的根节点
      return root;
   
    }
        //生成所有字符的哈夫曼编码
        public void CreateHfmDict(HfmTreeNode 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");
       
        }
        }
        //写哈夫曼编码长度
        public void WriteHfmCodeLength(String fileName){
        try{
        File file1=new File(fileName);
            //创建文件输出流
            FileOutputStream fos=new FileOutputStream(file1);
            //文件缓冲流
            BufferedOutputStream bos=new BufferedOutputStream(fos);
            for(int i=0;i<allCode.length;i++){
            int l=allCode[i].length();
            bos.write(l);
            }
            //关闭缓冲输出流
            bos.flush();
        bos.close();
        }catch(IOException e){
        e.getStackTrace();
        System.out.println("文件不存在!!!");
        }
       
       
        }
        //追加所有哈夫曼编码
        public String AppendHfmCodeData(){
        String s=Arrays.toString(allCode);
        s=s.replace("[","");
        s=s.replace(",", "");
        s=s.replace(" ", "");
        s=s.replace("]", "");
        System.out.println(s);
        return s;
       
        }
        //追加文件数据
        public StringBuffer AppendFileDataByHfmCode(String fileName){
        //可变字符串
        StringBuffer fileData=new StringBuffer();
        try{
       
        File file=new File(fileName);
            //创建文件输出流
             FileInputStream fis=new FileInputStream(file);
             //包装成缓冲文件
             BufferedInputStream bis=new BufferedInputStream(fis);
            int i;


          while ((i = bis.read()) != -1)
           {
          //读文件中的数据,翻译为哈夫曼编码
          String hfmCode=allCode[i];
            //追加
          fileData.append(hfmCode);
           }
       
         System.out.println(fileData);
         bis.close();
        }catch(IOException e){
        e.getStackTrace();
        System.out.println("文件不存在!!!");
        }
        finally{
       
        return fileData;
        }

        }
        //补零操作
        public  StringBuffer AppendZero( StringBuffer HfmData){
        //计数器   记录补零的数量
        int count=0;
        while(HfmData.length()%8!=0){
        HfmData=HfmData.append("0");
        count++;
        }
        //将十进制数转化为二进制字符串
        String countStr=Integer.toBinaryString(count);
        //补零
        while(countStr.length()<8){
        countStr="0"+countStr;
        }
        //加入补零数字串
        HfmData=HfmData.append(countStr);
        return HfmData;
       
        }
        //写文件
        public void WriteData(String fileName,StringBuffer HfmData){
        try{
        File file1=new File(fileName);
            //创建文件输出流
            FileOutputStream fos=new FileOutputStream(file1,true);
            //文件缓冲流
            BufferedOutputStream bos=new BufferedOutputStream(fos);
            while(HfmData.length()!=0){
            //截取HfmData[0,8)
            String substring=HfmData.substring(0, 8);
            //把截取串转化为十进制
            int parseInt=Integer.parseInt(substring, 2);
            System.out.println(parseInt);
            //把十进制数写入文件
            bos.write(parseInt);
            //删除截取的HfmData
            HfmData.delete(0,8);
            }
            //关闭缓冲输出流
            bos.flush();
        bos.close();
        }catch(IOException e){
        e.getStackTrace();
        System.out.println("文件不存在!!!");
        }
        }
 
}

package hmfTree;


import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
/*
 * 解压文件
 * 
 */
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;


public class test1 {

//保存所有字符个数
int[] charCount= new int[256];
Map<String ,Integer> keyCode=new HashMap<String ,Integer>();

     public static void main(String[] args){
    test1 t1=new test1();
    //得到哈夫曼编码和文件数据
    StringBuffer sb= t1.ReadHfmCodeLength("t1.txt");
    t1.HandleZero(sb);
    StringBuffer  data=t1.GenrateHfmCodeMap(sb);
    t1.WriteFileData("t3.txt", data);
     }
     //读取哈夫曼编码长度
     public StringBuffer ReadHfmCodeLength(String fileName){
    //可变字符串
    StringBuffer sb=new StringBuffer("");
    try{
     
    File file=new File(fileName);
    //文件输入流
    FileInputStream fis=new FileInputStream(file);
    BufferedInputStream bis=new BufferedInputStream(fis);
    //读文件的前256位
    int i;
    //计数器
    int count=0;
    while(true){
    if(count==256){
    break;
    }
    //读取到第i个
    i=bis.read();
    //设置第i个哈夫曼编码的长度
    charCount[count]=i;
     count++;
   
    }
   
    //读哈夫曼编码和文件数据
  while((i=bis.read())!=-1){
  //将十进制转化为二进制串
  String integerString =Integer.toBinaryString(i);
  //在前补零
  while(integerString.length()<8){
  integerString="0"+integerString;
  }
  System.out.println(integerString);
  //记录哈夫曼编码和文件数据    011100001111100000000010
  sb=sb.append(integerString);
 
        }
  System.out.println(sb);
     
    System.out.println(Arrays.toString(charCount));
    bis.close();
   
      }catch(IOException e){
    e.getStackTrace();
     
    }
return sb;
   
     
     }
   
   //消除补充的零
   public StringBuffer HandleZero(StringBuffer sb){
 // StringBuffer  data=new StringBuffer();
  //获取补零数值串
  String subString=sb.substring(sb.length()-8, sb.length());
  //转化为十进制
  int zeroCount=Integer.parseInt(subString, 2);
  System.out.println(zeroCount);
  //删除补零数值串


  sb.delete(sb.length()-8, sb.length());
  //得到倒数第二串8位
  String subString1=sb.substring(sb.length()-8, sb.length());
  sb.delete(sb.length()-zeroCount, sb.length());
  System.out.println(sb);
  return sb;
   }
   //得到哈夫曼字典
   public StringBuffer GenrateHfmCodeMap(StringBuffer sb){
  for(int i=0;i<charCount.length;i++){
  if(charCount[i]==0){
  continue;
  }
  if(charCount[i]!=0){
  //截取charCount[i]个
  String HfmCodeString=sb.substring(0, charCount[i]);
  //加入Map内
  keyCode.put(HfmCodeString, i);
  sb.delete(0, charCount[i]);
  
  }
  
  }
  System.out.println(keyCode);
  System.out.println(sb);


  return sb;
   }
   //写文件数据
   public void WriteFileData(String fileName,StringBuffer data){
  try{
    File file1=new File(fileName);
        //创建文件输出流
        FileOutputStream fos=new FileOutputStream(file1);
        //文件缓冲流
        BufferedOutputStream bos=new BufferedOutputStream(fos);
       
        //不包含key
         while((data.length())!=0){
        int i=1;
             String key="";
        key=data.substring(0, i);
    while(!keyCode.containsKey(key)){
  i++;
  key=data.substring(0, i);
 
    }
    //包含key
  bos.write(keyCode.get(key));
  data.delete(0, i);
    }
  
        //关闭缓冲输出流
        bos.flush();
    bos.close();
      }catch(IOException e){
    e.getStackTrace();
    System.out.println("文件不存在!!!");
      }
  
   }
  
}

总结:文件压缩最主要的是清楚的了解文件压缩的步骤,知道文件的io流中的怎样读文件和写文件和怎样操作二叉树,解决这三个问题,文件的压缩就几乎完成了;而解压缩是文件压缩的逆过程,清楚了文件的压缩过程文件的解压就不成问题了,具体过程就看下代码吧。


0 0
原创粉丝点击