`
qq_24665727
  • 浏览: 117996 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
社区版块
存档分类
最新评论
阅读更多
//这是我一个学长的,我看了好久才明白,给大家分享,这里的代码只是一个压缩方法的,还有
//一些类已经上传(测试类,结构类都在文件里面),需要可以下载,这个算法没有用递归遍历整个文件夹,所以之只能压缩
//一个文件,下面是主要压缩步骤:
//整个压缩文件的内容:(写入顺序)
 * 1.将原文件大小写入文件 dos.writeInt(fileSize);
 * 2.将码表的大小写入文件	dos.writeInt(mapSize);
 * 3.将每个字节写入文件fos.write(listBy.get(i));
 * 4.将每个字节对应的哈夫曼编码大小写入文件fos.write(codeSize);
 * 5.将每个字符对应的哈夫曼编码写入文件dos.writeChars(hfmcode_next);
 * 6.写入压缩后的字节数组的大小
 * 7.写入文件内容
//
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;

import javax.swing.tree.TreeNode;

/**
 * 整个压缩文件的内容:(写入顺序)
 * 1.将原文件大小写入文件 dos.writeInt(fileSize);
 * 2.将码表的大小写入文件	dos.writeInt(mapSize);
 * 3.将每个字节写入文件fos.write(listBy.get(i));
 * 4.将每个字节对应的哈夫曼编码大小写入文件fos.write(codeSize);
 * 5.将每个字符对应的哈夫曼编码写入文件dos.writeChars(hfmcode_next);
 * 6.写入压缩后的字节数组的大小
 * 7.写入文件内容
 * @author yan
 * 
 */
public class yasu {
	private String hashcode_path="D:\\实验文件夹\\HashCode.txt";//存储所有字节哈弗曼编码01串
	/**
	 * 读取文件
	 * 
	 * @param path
	 *            :文件路径
	 * @return:将文件的内容以字节数组的样式返回
	 */
	public static byte[] readFile(String path) {
	
		byte[] dataByte = null;
		try {
			java.io.FileInputStream fis = new java.io.FileInputStream(path);
			//int size = fis.available();// 可读的字节数
			File f = new File(path);
			long size1=f.length();//这样子也可以获取源文件的大小,并且还很准确。
			int size=(int)size1;
			dataByte = new byte[size];
			fis.read(dataByte);

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return dataByte;
	}

	/**
	 * 将码表的相关信息写入文件
	 * 
	 * @param fileSize
	 *            :原文件大小
	 * @param map
	 *            :存放码表的map
	 * @param listCh
	 *            :存放关键码的字符队列
	 * @param path
	 *            :文件路径
	 * @throws Exception
	 */
	public static void writeMap(int fileSize,
			java.util.HashMap<Byte, String> map, List<Byte> listBy, String path)
			throws Exception {

		java.io.FileOutputStream fos = new java.io.FileOutputStream(path);
		java.io.DataOutputStream dos = new java.io.DataOutputStream(fos);

		dos.writeInt(fileSize);//1. 将原文件大小写入文件
		int mapSize = map.size();// 码表的大小
		dos.writeInt(mapSize);// 2.将码表的大小写入文件
		for (int i = 0; i < mapSize; i++) {
			fos.write(listBy.get(i));// 3.将每个字节写入文件
			String hfmcode_next = map.get(listBy.get(i));// 得到每个字节对应的哈夫曼编码
			byte codeSize = (byte) hfmcode_next.length();
			fos.write(codeSize);// 4.将每个字节对应的哈夫曼编码大小写入文件
			dos.writeChars(hfmcode_next);// 5.将每个字符对应的哈夫曼编码写入文件
		}
		dos.flush();
		fos.close();
	}

	/**
	 * 将压缩好的字节数组写入文件
	 * 
	 * @param b
	 *            :压缩好的字节数组
	 * @param path
	 *            :文件路径
	 */
	public static void writeFile(byte[] b, String path) {
		try {
			java.io.FileOutputStream fos = new java.io.FileOutputStream(path,
					true);
			java.io.DataOutputStream dos = new java.io.DataOutputStream(fos);
			// 写入字节数组的大小
			dos.writeInt(b.length);
			fos.write(b);
			fos.flush();
			fos.close();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}



	
	/**
	 * 将10字符串以8个为一组转化为一个字节数组
	 * 
	 * @param str
	 * @return
	 */
	//String ->char[]->byte( char数组转换成byte数组 然后把一个8个字节大小的byte数组转换成一个2进制的值,然后强制转型为byte   实现压缩。。。结果得到一个byte类型的值)->
	private byte[] StringToByteArray(String str) {
		char[] c = str.toCharArray();// 将字节串str转化为字符数组c
		int len = c.length;// 字符串字符的个数
		int lenByte;
		String s = "";
		char c_next;
		byte[] b;//存放已经转换成字节的01串
		if (len % 8 == 0) {// 如果字符串的长度能被8整除
			lenByte = len / 8 + 1;//+1是因为最后一个要存放补0的个数
			b = new byte[lenByte];
			for (int i = 0; i < lenByte - 1; i++) {
				for (int j = i * 8; j < (i + 1) * 8; j++) {
					c_next = c[j];
					s = s + c_next;//第i个组的01串,每8个一组(分离出8个01串字符,)
				}
				//System.out.println("第" + i + "个字符串:" + s);
				System.out.println("进入转化8个01串的方法");
				b[i] = CharArrayToByte(s);//把一组01字符串转化成一个字节
				s = "";
				//System.out.println("第" + i + "个字符串转化为字节后的值:" + b[i]);
			}
			b[lenByte - 1] = 0;// 字节数组的最后一个存放补0的个数
		} else {// 如果字符串的长度不能被8整除

			lenByte = len / 8 + 2;
			b = new byte[lenByte];
			int remainder = len % 8;// 求出除8的余数
			int zeroNum = 8 - remainder;// 补0的个数
			//System.out.println("补0数:" + zeroNum);
			//System.out.println("原字符串:" + str);
			for (int i = 0; i < zeroNum; i++) {
				str = str + '0';// 在字符串后面补0
			}
			//System.out.println("补0后的字符串:" + str);
			c = str.toCharArray();
			//System.out.println("补0后的字符串的字符个数:" + c.length);
			for (int i = 0; i < lenByte - 1; i++) {
				for (int j = i * 8; j < (i + 1) * 8; j++) {
					c_next = c[j];
					s = s + c_next;
				}
				//System.out.println("第" + i + "个字符串:" + s);
				b[i] = CharArrayToByte(s);
				s = "";
				//System.out.println("第" + i + "个字符串转化为字节后的值:" + b[i]);
			}
			b[lenByte - 1] = (byte) zeroNum;// 字节数组的最后一个存放补0的个数
		}
		return b;
	}
	
	/**
	 * 将8字符串(8个字节)转化为一个字节,(其实这里便是压缩过程。。。)
	 * 把一个8个字节大小的byte数组转换成一个2进制的值,然后强制转型为byte   实现压缩。。。
	 * @param str: 传入的8字符串
	 *            
	 * @return: 一个字节
	 */
	private byte CharArrayToByte(String str) {
		char[] c = str.toCharArray();// 将字符串str转化为字符数组c
		int len = c.length;
		byte[] b = new byte[len];
		byte value = 0;
		byte value_next;
		for (int i = 0; i < len; i++) {
			b[i] = Byte.parseByte(c[i] + "");//此方法将返回由十进制参数表示的字节值
			// System.out.println(b[i]);
		}
		//把一个8个字节大小的byte数组转换成一个2进制的值,然后强制转型为byte  8位就是2的8次方,则最大为256      实现压缩。。。。。
		for (int i = 0; i < len; i++) {
			value_next = (byte) (b[i] * Math.pow(2, len - i - 1));// 幂计算,括号里面计算一组01串的二进制数
			value = (byte) (value + value_next);
	//b[i] * Math.pow(2, len - i - 1)这个计算的是一个没有符号位的8位01串,它的范围是0到256,但是byte是-128到127,所以会出现负值
	//在解压的时候转换成int类型时候+256
		}
		return value;
	}
	/**
	 * 把哈弗曼编码01串存入文件  
	 */
	public static void Save_hashcode(String path,String hfmcode){
		try {
			FileWriter fw=new FileWriter(path);
			BufferedWriter bw=new BufferedWriter(fw);
			bw.write(hfmcode);
			bw.flush();
			fw.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * 压缩文件
	 * 
	 * @param path1
	 *            :原文件路径
	 * @param path2
	 *            :压缩后的文件路径
	 * @throws Exception
	 */
	public void CompressFile(String path1, String path2) throws Exception {
		// 从文件中得到字节数组
		System.out.println("进入压缩方法");
		byte[] b = yasu.readFile(path1);
		int b_size = b.length;// 原文件大小
		byte[] b_compress;// 字节数组,存放压缩的字符串

		 String hfmcode = "";// 文件内所有字节的哈夫曼编码
		String hfmcode_next;// 文件中每个字节的哈夫曼编码

		// ********上面那么多就是想要得到码表和存放关键码队列
		Tree hfm = new Tree();
		HashMap<Byte, String> map = hfm.M(path1);//这个是存有byte和相应的编码的haspmap键值对
		// 接下来获得存放关键码的队列(存有字节名称的list集合)
		List<Byte> listBy = hfm.L(path1);

		for (int i = 0; i < b_size; i++) {
			// 得到每个字节的哈夫曼编码
			hfmcode_next = map.get(b[i]); // 字节b[i]对应的哈夫曼编码
		//	System.out.println("第" + i + "个: " + b[i] + "的编码:" + hfmcode_next);
			hfmcode = hfmcode + hfmcode_next;// 将每个字节的哈夫曼编码依次相加为一个01字符串
		}
		// hfmcode存放源文件所有字节一一对应的哈夫曼编码
		//System.out.println("01串大小:" + hfmcode.length());
		//System.out.println("01串:" + hfmcode);
		char[] ch = hfmcode.toCharArray(); // 将源文件的哈夫曼编码转化成字符数组
		//System.out.println("01串的大小:" + ch.length);
		// 将源文件的哈夫曼编码转化 得到对应的字节数组,这个方法StringToByteArray(hfmcode);
		//实现了将8个byte字节转换成一个2进制数然后又转换为byte,实现压缩
		b_compress = StringToByteArray(hfmcode);
		//for (int i = 0; i < b_compress.length; i++) {
			//System.out.println("第" + i + "个字节" + b_compress[i]);
	//	}
		System.out.println("进入写入***********");
		// 1.将文件大小和码表相关信息写入文件
		writeMap(b_size, map, listBy, path2); 
		// 2.将字节数组写入文件
		writeFile(b_compress, path2);
		Save_hashcode(hashcode_path,hfmcode);
		System.out.println("完成!!");
	}

 

0
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics