文件压缩与解压

  • 文件压缩

通过某种特殊的编码方式将数据信息中存在的重复度、冗余度有效地降低,从而达到数据压缩的目的。这里用的是哈夫曼树产生特殊编码。

//compress.h
#pragma once
typedef unsigned long long longType;
struct CharInfo
{
	unsigned char _ch;//字母信息
	longType _count;  //出现次数
	string _code;     //哈夫曼编码
	CharInfo(){}
	CharInfo(longType count)
		:_count(count)
		, _ch(0)
	{}
	bool operator!=(const CharInfo& ch)const
	{
		return _count != ch._count;
	}
	longType operator+(const CharInfo& ch)const
	{
		return _count + ch._count;
	}
	bool operator<(const CharInfo& ch)const
	{
		return _count < ch._count;
	}
};

class FileCompress
{
public:
	FileCompress()
	{
		for (int i = 0; i < 256; ++i)
		{
			_infos[i]._ch = i;
			_infos[i]._count = 0;
		}
	}
public:
	//压缩
	void Compress(const char *filename)
	{
		assert(filename);
		FILE *fout = fopen(filename, "rb");
		assert(fout);
		unsigned char ch = fgetc(fout);
		while (!feof(fout))
		{
			_infos[ch]._count++;
			ch = fgetc(fout);
		}
		//构造哈夫曼树
		CharInfo invalid(0); 
		HuffmanTree<CharInfo> tree(_infos, 256, invalid);
		//生成哈夫曼编码
		string code;
		GenerateHuffmanCode(tree.GetRootNode(), code);
		//压缩文件名称
		string compressfilename = filename;
		compressfilename += ".compress";
		FILE* fin = fopen(compressfilename.c_str(), "wb");
		assert(fin);
		fseek(fout, 0, SEEK_SET);//文件起始的位置
		ch = fgetc(fout);
		char value = 0;
		int pos = 0;

		while (!feof(fout))
		{
			string& code = _infos[(unsigned char)ch]._code;
			for (size_t i= 0; i < code.size(); ++i)
			{
				value <<= 1;
				if (code[i] == ‘1‘)
				{
					value |= 1;
				}
				if (++pos == 8)
				{
					fputc(value, fin);
					value = 0; 
					pos = 0;
				}
			}
			ch = fgetc(fout);
		}
		if (pos != 0)
		{
			value <<= (8 - pos);
			fputc(value, fin);
		}
		//写配置文件
		string configfilename = filename;
		configfilename += ".config";
		FILE* finconfig = fopen(configfilename.c_str(), "wb");
		assert(finconfig);
		char buffer[128];
		string str;
		for (size_t i = 0; i < 256; ++i)
		{
			if (_infos[i]._count>0)
			{
				str += _infos[i]._ch;
				str += ‘,‘;
				sprintf(buffer,"%d",_infos[i]._count);
				str += buffer;
				str += ‘\n‘; 
				fputs(str.c_str(), finconfig);
				str = "";
			}

		}
		fclose(finconfig);
		fclose(fout);
		fclose(fin);
	}
	bool ReadLine(FILE *&fout, string&str)
	{
		char ch = fgetc(fout);
		if (feof(fout))
			return false;
		//while (ch != EOF)
		while (!feof(fout))
		{
			str += ch;
			ch = fgetc(fout);
			if (ch == ‘\n‘)
			{
				break;
			}
		}
		/*while (ch != ‘\n‘)
		{
			str += ch;
			ch = fgetc(fout);
		}*/
		return true;
	}
	//解压
	void UnCompress(const char *filename)
	{
		//从配置文件中读取文件出现的次数
		string configfilename = filename;
		configfilename += ".config";
		FILE* foutconfig = fopen(configfilename.c_str(), "rb");
		assert(foutconfig);

		string str;
		longType count = 0;
		while (ReadLine(foutconfig, str))
		{
			_infos[(unsigned char)str[0]]._count = atoi(str.substr(2).c_str());
			count += _infos[(unsigned char)str[0]]._count;
			//string a=s.substr(0,5); 
			//获得字符串s中 从第0位开始的长度为5的字符串//默认时的长度为从开始位置到尾
			str.clear();
		}
		//建立哈夫曼树
		CharInfo invalid(0);
		HuffmanTree<CharInfo> tree(_infos, 256, invalid);

		//读压缩文件
		string compressfile = filename;
		compressfile += ".compress";
		FILE *fout = fopen(compressfile.c_str(), "rb");
		assert(fout);
		//建立解压文件
		string uncompressfile = filename;;
		uncompressfile += ".uncompress";
		FILE* fin = fopen(uncompressfile.c_str(), "wb");
		assert(fout);
		unsigned char ch = fgetc(fout);
		HuffmanNode<CharInfo>* _root = tree.GetRootNode();
		HuffmanNode<CharInfo>* cur = _root;
		int pos = 8;
		while (!feof(fout))
		{
			if (ch & 1 << (pos-1))
			{
				cur = cur->_right;
			}
			else
			{
				cur = cur->_left;
			}
			if (cur->_left == NULL&&cur->_right == NULL)
			{
				fputc(cur->_weight._ch, fin);
				cur = _root;
				--count;
				if (count == 0)
				{
					break;
				}
			}
			--pos;
			if (pos == 0)
			{
				pos = 8;
				ch = fgetc(fout);
			}

		}
		fclose(foutconfig);
		fclose(fout);
		fclose(fin);

	}

protected:
	void GenerateHuffmanCode(const HuffmanNode<CharInfo> *_root, string code)
	{
		if (_root == NULL)
		{
			return;
		}
		if (_root->_left)
			GenerateHuffmanCode(_root->_left, code + ‘0‘);
		if (_root->_right)
			GenerateHuffmanCode(_root->_right, code + ‘1‘);
		if (_root->_left == NULL&&_root->_right == NULL)
		{
			_infos[(_root->_weight)._ch]._code = code;
		}
	}
protected:
	CharInfo _infos[256];
};
//heap.h
#pragma once
#include<vector>
template<class T>
struct small
{
	bool operator()(const T &data1, const T &data2)
	{
		return data1 < data2;
	}
};
template<class T>
struct big
{
	bool operator()(const T &data1, const T &data2)
	{
		return data1>data2;
	}
};
//template<class T,template<class>class compare=big>
template<class T, class compare = big<T>>
class Heap
{
public:
	Heap()
	{}
	Heap(const T*&a, size_t size)
	{
		_a.reserve(size);
		//reserve用来(预留空间,)改变capacity,
		//不改变size,会去分配内存,但不会构造出对象;
		//如果改变后的capacity比当前capacity大,则capacity会变大;
		//反之,capacity不变。可以用下面的代码去测试
		for (size_t i = 0; i < size; ++i)
		{
			_a.push_back(a[i]);
		}
		for (int i = (_a.size() - 2) / 2; i >= 0; --i)
		{
			_AdjustDown(i);
		}
	}
	Heap(const Heap<T>& h)
	{
		_a = _Copy(h->_a);
	}
	~Heap()
	{
		//vector会自动析构
	}
	void Push(const T &data)
	{
		_a.push_back(data);
		_AdjustUp(_a.size() - 1);
	}
	void Pop()
	{
		swap(_a[0], _a[_a.size() - 1]);
		_a.pop_back();
		_AdjustDown(0);
	}
	void Print()
	{
		_Print(_a);
		cout << endl;
	}
	bool Empty()
	{
		return (_a.size() == 0);
	}
	T& Top()
	{
		return _a[0];
	}
	size_t Size()
	{
		return _a.size();
	}
protected:
	void _AdjustDown(size_t parent)
	{
		compare com;
		size_t child = parent * 2 + 1;
		while (child < _a.size())
		{
			if (child + 1 < _a.size() && com(_a[child + 1], _a[child]))
			{
				++child;
			}
			if (com(_a[child], _a[parent]))
			{
				swap(_a[parent], _a[child]);
				parent = child;
				child = parent * 2 + 1;
			}
			else
			{
				break;
			}
		}
	}
	void _AdjustUp(size_t child)
	{
		compare com;
		size_t parent = (child - 1) / 2;
		while (child > 0)
		{
			if (com(_a[child], _a[parent]))
			{
				swap(_a[child], _a[parent]);
				child = parent;
				parent = (child - 1) / 2;
			}
			else
			{
				break;
			}
		}
	}
	vector<T> _Copy(vector<T>&_a)
	{
		vector<T> a;
		a.resize(_a.size());
		for (int i = 0; i < _a.size(); ++i)
		{
			a[i] = _a[i];
		}
		return a;
	}
	void _Print(vector<T>&_a)
	{
		for (size_t i = 0; i < _a.size(); ++i)
		{
			cout << _a[i] << " ";
		}
	}

protected:
	vector<T> _a;
};
huffmanTree.h
#pragma once
template<class T>
struct HuffmanNode
{
	HuffmanNode<T>*  _left;
	HuffmanNode<T>* _right;
	T _weight;
	HuffmanNode(const T& value)
		:_left(NULL)
		, _right(NULL)
		, _weight(value)
	{}
};
//template<class T>

template<class T>
class HuffmanTree
{
	typedef HuffmanNode<T> Node;
	//friend void Clear(Node* _root);
public:
	HuffmanTree()
	{}
	HuffmanTree(const T* a, size_t size, const T& invalid)
	{
		_root = _CreateTree(a, size, invalid);
	}
	Node* GetRootNode()
	{
		return _root;
	}
protected:
	Node* _CreateTree(const T*&a, size_t size, const T&invalid)
	{
		struct Compare
		{
			bool operator()(const HuffmanNode<T>* node1, const HuffmanNode<T>* node2)
			{
				return node1->_weight < node2->_weight;
			}
		};
		Heap<Node*, Compare> minheap;
		for (size_t i = 0; i < size; i++)
		{
			if (a[i] != invalid)
				minheap.Push(new Node(a[i]));
		}
		while (minheap.Size()>1)
		{
			Node* left = minheap.Top();
			minheap.Pop();
			Node* right = minheap.Top();
			minheap.Pop();
			Node* parent = new Node((left->_weight) + (right->_weight));
			parent->_left = left;
			parent->_right = right;
			minheap.Push(parent);
		}
		return minheap.Top();
	}

protected:
	Node* _root;
};

运行结果:

时间: 2024-12-18 00:30:32

文件压缩与解压的相关文章

iOS开发——网络编程OC篇&amp;(八)文件压缩与解压

文件压缩与解压 一.技术方案1.第三方框架:SSZipArchive2.依赖的动态库:libz.dylib 二.压缩11.第一个方法/** zipFile :产生的zip文件的最终路径 directory : 需要进行的压缩的文件夹路径 */[SSZipArchive createZipFileAtPath:zipFile withContentsOfDirectory:directory]; 2.第一个方法/** zipFile :产生的zip文件的最终路径 files : 这是一个数组,数组

文件压缩、解压工具类。文件压缩格式为zip

package com.JUtils.file; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.zip.ZipEntry; impor

Linux 各种类型文件 压缩、解压

个人博客首页(点击查看详情) -- https://blog.51cto.com/11495268个人微信公众号(点击查看详情) -- https://blog.51cto.com/11495268/2401194     1.简介     Linux 环境下 一切皆文件,本文描述 关于 各种类型的 文件压缩.解压 操作     2.文件压缩格式      3.zip 格式 3.1 工具安装 # apt-get install zip      3.2 压缩 # zip -r zip.zip z

Java实现文件压缩与解压[zip格式,gzip格式]

Java实现ZIP的解压与压缩功能基本都是使用了Java的多肽和递归技术,可以对单个文件和任意级联文件夹进行压缩和解压,对于一些初学者来说是个很不错的实例. zip扮演着归档和压缩两个角色:gzip并不将文件归档,仅只是对单个文件进行压缩,所以,在UNIX平台上,命令tar通常用来创建一个档案文件,然后命令gzip来将档案文件压缩. Java I/O类库还收录了一些能读写压缩格式流的类.要想提供压缩功能,只要把它们包在已有的I/O类的外面就行了.这些类不是Reader和Writer,而是Inpu

linux下文件压缩与解压操作

对于刚刚接触Linux的人来说,一定会给Linux下一大堆各式各样的文件名给搞晕.别个不说,单单就压缩文件为例,我们知道在Windows下最常见的压缩文件就只有两种,一是,zip,另一个是.rap.可是Linux就不同了,它有.gz..tar.gz.tgz.bz2..Z..tar等众多的压缩文件名,此外windows下的.zip和.rar也可以在Linux下使用,不过在Linux使用.zip和.rar的人就太少了.本文就来对这些常见的压缩文件进行一番小结,希望你下次遇到这些文件时不至于被搞晕.

实现asp.net的文件压缩、解压、下载

很早前就想做文件的解压.压缩.下载 了,不过一直没时间,现在项目做完了,今天弄了下.不过解压,压缩的方法还是看的网上的,嘻嘻~~不过我把它们综合了一下哦.呵呵~~ 1.先要从网上下载一个icsharpcode.sharpziplib.dll 2.建立类AttachmentUnZip,内容如下: using System;using System.Data;using System.Configuration;using System.Web;using System.Web.Security;u

C# 文件压缩与解压(ZIP格式)

在企业开发过程中经常会遇到文件的压缩与解压,虽然网上很多流行的压缩文件格式都是RAR的,但是由于RAR不是一个开放的标准,因此ZIP成了更多人的选择.如果你不想自己开发的话可以选择开源的项目,比如SharpZipLib就是一个不错的选择. using System; using System.Collections.Generic; using System.Text; using System.IO; using ICSharpCode.SharpZipLib.Zip; using Syste

java实现文件压缩与解压

用java实现文件的压缩与解压是很常见的功能. 我最爱上代码: 1 import java.io.File; 2 import java.util.ArrayList; 3 import java.util.List; 4 5 import net.lingala.zip4j.core.ZipFile; 6 import net.lingala.zip4j.model.ZipParameters; 7 import net.lingala.zip4j.util.Zip4jConstants; 8

C# 文件压缩与解压

压缩部分:         try            {                string Rarexe = @"C:\Program Files\WinRAR\WinRAR.exe";                 //WinRAR.exe 的完整路径                string mulu = @"F:\仓存数据\";                // 子文件所在目录                string fileList