`
YL之城
  • 浏览: 20636 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
社区版块
存档分类
最新评论

文件的压缩

 
阅读更多

本节主要是利用huffman树的原理来对文件进行处理,从而达到压缩文件的效果。huffman树又称为最优二叉树。是带权路径最短的树。

先说说怎么建huffman树,其构造方法为:

1.根据给定的n个权值的结点,选出两个结点值最小的数作为左、右子树,这个二叉树的根结点为左、右结点的权值之和。

2.将新的权值加入到剩余结点中,删除原来的两个结点

3.重复1 2,直到最后只有一个结点为止。

Huffman压缩是一个无损的压缩算法。通过构建huffman树,可以得到每个叶结点的huffman编码,然后把源文件的字节用huffman编码来存储,从而达到减小空间占用,实现压缩。

要实现文件的压缩,可以分为如下几步:

一、根据传入的文件,统计每个字节出现的次数

二、根据每个字节出现的次数,构建一棵huffman树

三、根据huffman树,得到每个字节的huffman编码

四、把源文件和huffman编码写入文件中去

通过这几步就基本上可以实现文件的压缩。

第一步:

 

/**
	 * 根据传入的文件,统计每个字节出现的次数
	 * @param path	文件的路径
	 * @return	int数组
	 */
	public int[] fileByteCount(String path){
		//存储文件中每个字节出现的次数
		try{
			FileInputStream fis=new FileInputStream(path);
			BufferedInputStream bis=new BufferedInputStream(fis);
			while(fis.available()>0){
				//文件是否读完
				int i=fis.read();
				byteCount[i]++;	//用数组存储每个字节出现的次数		
			}
			fis.close();
			bis.close();
		}catch(Exception ef){
			ef.printStackTrace();
		}	
		return byteCount;
	}

 第二步:

/**
	 * 创建最优二叉树的方法
	 * @param arr:传入的数组
	 * @param TreeNode:返回根结点
	 */
	public TreeNode createHuffman(int[] arr){
		//实例化一个优先队列对象
		PriorityQueue<TreeNode> queue = new PriorityQueue<TreeNode>(11,new MyComparator());
		TreeNode root=null;
		//遍历数组,将数组元素构建成结点,并添加到队列中
		for (int i=0;i<arr.length;i++){
			if(arr[i]!=0){
				//创建结点,结点值不为0
				TreeNode node = new TreeNode(i,arr[i]);
				//将结点添加到队列中
				queue.add(node);
			}
		}
		//遍历队列,每次取出两个最小元素作为叶子结点,它们的和作为父结点建立二叉树,
		//并从队列中删除这两个元素,同时把它们的父结点添加到队列中
		while(queue.size()>1){
			//同时取两个最小元素
			TreeNode node1 = queue.poll();
			TreeNode node2 = queue.poll();			
			//根据取得的元素创建父结点
			TreeNode fnode = new TreeNode(0,node1.getZijie()+node2.getZijie());			
			//建立引用关系
				fnode.setLeft(node1);
				fnode.setRight(node2);
				node1.setParent(fnode);
				node2.setParent(node2);		
			//将父结点添加到队列中
			queue.add(fnode);				
		}	
		root =queue.peek();
		return root;
	}	

 第三步:

/**
	 * 根据根结点创建哈夫曼编码
	 * 规则:左子结点为:1,右子结点为:0
	 * @param root:根结点
	 */
	public void createCode(TreeNode root,String code){
		//首先是确定各结点的路径
			//得到子结点
			TreeNode left = root.getLeft();	
			TreeNode right = root.getRight();
			//打印叶子节点
			if (left==null&&right==null){				
				System.out.println(root.getObj()+"的编码为:"+code);
				//byteCode 的下标是字节,值为其哈夫曼编码
				byteCode[(Integer)root.getObj()]=code;
			}
			if (left!=null){
				//递归
				createCode(left,code+"0");
			}
			if (right!=null){
				//递归
				createCode(right,code+"1");
			}
	}

 第四步:是最重要的一步,也是最关键的一步:

/**
	 * 把源文件和huffman编码写入文件中去
	 * @param path	源文件路径
	 * @param path1	要写入的文件路径
	 * @param str	huffman编码的String数组
	 */
	public void writeToFile(String path,String path1,String []str){
		try{
			FileOutputStream fos = new FileOutputStream(path1);
			DataOutputStream Dos = new DataOutputStream(fos);// 创建输出流	
			for (int k = 0; k< str.length; k++) {
				if (str[k] != null){ 
					Dos.writeInt(k);
					Dos.writeInt(str[k].length());	
				}else{
					str[k]="";
					Dos.writeInt(k);
					Dos.writeInt(0);
				}			
			}	
			//先把编码写入文件
			int count=0;//记录中转的字符个数
			int i=0;//第i个字节
			String writes="";
			String tranString ="";
			String waiteString ;
			while(i<256||count>=8){
				//等待的字符大于8
				if(count>=8){
					waiteString="";
					//讲writes前8位取出
					for (int t = 0; t < 8; t++) {
						waiteString = waiteString + writes.charAt(t);
					}
					// 将writes前八位去掉
					if (writes.length() > 8) {
						tranString = "";
						for (int t = 8; t < writes.length(); t++) {
							tranString = tranString + writes.charAt(t);
						}
						writes = "";
						writes = tranString;
					}else {
						//刚好只有8位
						writes = "";
					}
					count = count - 8;// 写出一个8位的字节
					int intw = changeString(waiteString);// 得到String转化为int
					// 写入文件
					Dos.writeInt(intw);
				}else if(count<8){
					// 得到第i个编码信息等待写入
					if (str[i]!= null ) {
						count = count + str[i].length();
						if(str[i].length()!=0){
						}
						writes = writes + str[i];
						i++;
					}
				}
			}
			// 把所有编码没有足够8的整数倍的String补0使得足够8的整数倍,在写入
			if (count > 0&&count<8) {
				waiteString = "";// 清空要转化的编码
				int buzero=0;
				for (int t = 0; t < 8; t++) {
					if (t < writes.length()) {
						waiteString = waiteString + writes.charAt(t);
					} else {
						waiteString = waiteString + "0";
						//补了多少个0
						buzero++;	
					}
				}
				Dos.writeInt(changeString(waiteString));
				Dos.writeInt(buzero);
			}
			try{
				// 将源文件中的所有byte转化为01字符串,写入压缩文件
				FileInputStream fis = new FileInputStream(path);
				BufferedInputStream bis = new BufferedInputStream(fis);
				count =0;
				writes="";
				tranString ="";
				int idata=bis.read();
				while(bis.available()>0||count>=8){
					//如果缓冲区等待写入的字符超过8
					if(count>=8){
						waiteString="";
						for (int t = 0; t < 8; t++) {
							waiteString = waiteString + writes.charAt(t);
						}
						// 将前八位删掉
						if (writes.length() > 8) {
							tranString = "";
							for (int t = 8; t < writes.length(); t++) {
								tranString = tranString + writes.charAt(t);
							}
							writes = "";
							writes = tranString;

						} else {
							writes = "";
						}
						count = count - 8;// 写出一个8位的字节
						int intw = changeString(waiteString);
						Dos.writeInt(intw);
					}else {
						// 如果不够8位,就继续取下一个字节
						count = count + str[idata].length();
						writes = writes + str[idata];
						idata = bis.read();
					}					
				}
				count = count + str[idata].length();
				writes = writes + str[idata];
				// 把count剩下的写入
				int endsint = 0;
				if (count > 0) {
					waiteString = "";// 清空要转化的码
					for (int t = 0; t < 8; t++) {
						if (t < writes.length()) {
							waiteString = waiteString + writes.charAt(endsint);
						} else {
							waiteString = waiteString + '0';
							endsint++;
						}
					}
					Dos.writeInt(changeString(waiteString));// 写入所补的0;
					Dos.writeInt(endsint);
					System.out.println(endsint);
					Dos.flush();
				}
				fis.close();
				bis.close();
				fos.close();
				Dos.close();
			}catch(Exception ef){
				ef.printStackTrace();
			}
		}catch(Exception ef){
				ef.printStackTrace();
		}
	}

 然后根据源文件的路径,调用方法,并制定生成的文件路径及文件名,这样就可以进行文件压缩啦。但这只是简单的压缩,可能对一些小文件进行压缩时,压缩的文件比源文件可能还大,这样还不如不压缩,这里可能还存在一些小问题,希望牛人指出。

 

 

 

<!--EndFragment-->
分享到:
评论

相关推荐

    用哈夫曼编码实现文件压缩(代码+报告)

    数据结构课程设计用哈夫曼编码实现文件压缩: 一、实验题目: 用哈夫曼编码实现文件压缩 二、实验目的: 1、了解文件的概念。 2、掌握线性链表的插入、删除等算法。 3、掌握Huffman树的概念及构造方法。 4、掌握...

    C# 文件压缩-指定文件压缩

    C# 文件压缩-指定文件压缩

    多文件压缩与解压程序 实验报告

    1. 分析给出的多文件打包/解包程序MyZip和单文件压缩程序Compress,将程序MyZip改写为一个能够处理多文件压缩/解压的控制台程序,可利用命令行参数控制其完成如下功能: 1. 将命令行参数指定的一组文件压缩为一个...

    asp.net调用RAR实现文件压缩与解压缩图文代码

    如果服务器上安装了RAR程序,那么asp.net可以调用RAR实现文件压缩与解压缩。 不过要注意的是,由于Web程序不能直接调用客户端的程序(除非用ActiveX,ActiveX几乎被废弃),所以如果要想实现让用户把本地文件用网页...

    1G的文件压缩成1M的方法.rar

    1G的文件压缩成1M的方法1G的文件压缩成1M的方法.rar1G的文件压缩成1M的方法.rar1G的文件压缩成1M的方法.rar1G的文件压缩成1M的方法.rar1G的文件压缩成1M的方法.rar1G的文件压缩成1M的方法.rar1G的文件压缩成1M的方法...

    JAVA文件压缩与解压缩实践(源代码+论文)

    JAVA文件压缩与解压缩实践(源代码+论文),详细文档分析!

    1G的文件压缩成1M的方法

    1G的文件压缩成1M的方法,很多网上下载的文件只有300MB或400MB,但是解压后,居然可以达到2GB甚至更多,也许你会奇怪,为什么你用WinRAR压缩同样的文件,就没有这样的压缩效果呢?其实这是因为这些文件是用多款不同...

    适合练手、课程设计、毕业设计的Java项目源码:文件压缩与解压缩实践(源代码+论文).rar

    适合练手、课程设计、毕业设计的Java项目源码:文件压缩与解压缩实践(源代码+论文).rar 适合练手、课程设计、毕业设计的Java项目源码:文件压缩与解压缩实践(源代码+论文).rar 适合练手、课程设计、毕业设计的Java...

    JAVA文件压缩与解压缩实践.doc

    JAVA文件压缩与解压缩实践报告 主函数 gzip压缩模块代码 压缩模块要完成的就是将文件读入以后进行压缩,再将压缩后的数据写入一个新的文件,其部分代码如下: public class gzip { public static void main(String...

    Java把文件压缩成zip

    Java把文件压缩成zip,粘贴在项目中即可使用

    C++ Zlib库实现zip文件压缩解压(支持递归压缩)

    C++利用Zlib库实现zip文件压缩及解压 支持递归压缩.可配合自动更新功能实现zip压缩包进得软件更新

    用哈夫曼编码实现文件压缩

    利用哈夫曼编码思想,设计对一个文本文件(.txt)中的字符进行哈夫曼编码,生成编码压缩文件(.txt),并且还可将压缩后的文件进行解码还原为原始文本文件(.txt)。 实现的功能: (1)压缩:实现对文件的压缩,生成...

    教你如何将1G文件压缩成1M

    教你如何将1G文件压缩成1M 实用啊

    c语言实现文件压缩 huffman编码实现

    c语言实现文件压缩,用huffman编码实现。并修改注册表实现鼠标右击出现如同rar的简单操作。

    C# RAR 文件压缩

    C# rar 文件压缩 .net 压缩文件 RAR

    C#实现文件压缩

    利用C#实现文件压缩 并生成文件的xml文档说明

    java实现多个文件压缩

    java实现多个文件压缩

    图形文件压缩工具

    太好用的图形文件压缩软件,它可以满足文件尺寸大小不变可文件体积大幅减小。而清晰度几乎不变。

    文件压缩-C语言

    哈夫曼编码是一种常用的数据压缩技术,对数据文件进行哈夫曼编码可大大缩短文件的传输长度,提高信道利用率及传输效率。要求采用哈夫曼编码原理,统计文本文件中字符出现的词频,以词频作为权值,对文件进行哈夫曼...

Global site tag (gtag.js) - Google Analytics