ファイルベースのハフマン圧縮アルゴリズムLZ77アルゴリズムと、(c)

ファイルベースのハフマン圧縮アルゴリズムLZ77アルゴリズムと、(c)

ファイル圧縮に基づいて、LZ77アルゴリズムとハフマンアルゴリズム()及び
LZ77アルゴリズムとハフマンアルゴリズムファイル圧縮(B)に基づいて、基本原則とプロセス全体のハフマン圧縮ファイル圧縮を説明する、プロセスを説明するためにファイルを抽出

まず、エンコーディングHU FF男解凍ソースファイルを使用して

プロセス全体を解凍します。

  1. 圧縮されたファイルからソースファイルの接尾辞を取得します。
  2. 行の合計数で圧縮したファイルからの文字数を取得します。
  3. 各文字が表示された回数を取得します。
  4. 復興HU FF男ツリー
  5. 減圧

II。圧縮ファイルの接尾辞からソースを取得

あなたは、ファイルを解凍したい場合は那么就需要Huffman树必要に応じてハフマン木就需要字符频度信息そして、最終的には、ファイルに保存され出したデータを解凍し、あなたがする必要があります获取文件后缀信息そして、タグ情報は、あなたが直接読み取ることができ、それらをアーカイブする圧縮ファイルの時に書かれています。

読み取りラインを容易にするために、第一の機能パッケージ:

//读一行函数
void FileCompressHuffman::ReadLine(FILE* fIn, std::string& strInfo) 
{
	assert(fIn);

  //注意这里的feof是针对二进制文件的,因为我们为了解决可以压缩汉字的相关问题,
  //选择以二进制的方式打开,并不是以文本文件的方式打开,文本文件的结束标识是EOF,
  //而二进制文件的结束标识是FEOF
	while (!feof(fIn))
	{
		char ch = fgetc(fIn);
		if (ch == '\n')
			break;
		strInfo += ch;
	}
}

注意:

  • ここにいることを注意feof是针对二进制文件するので、私たちは漢字に関連した問題を解決するために圧縮することができ、選択しオープンバイナリように、テキスト・ファイルは、テキストファイルがEOFである識別を終了開き、バイナリファイル識別子の端部は、FEOFではないように

ファイルの接尾辞を読みます

//文件后缀
	std::string strFilePostFix;
	ReadLine(fIn, strFilePostFix);

III。行の総数で圧縮されたファイルから文字の数を取得し

//读取文件数据的行数
	std::string strCount;
	ReadLine(fIn, strCount);
	int lineCount = atoi(strCount.c_str());

IV。各文字が表示されますのための発生情報を取得します

for (int i = 0; i < lineCount; ++i) 
  {
    //记录读取每一行的数据
		std::string strchCount;
		ReadLine(fIn, strchCount);

    //如果读到的数据为空,说明可能读到了换行符
		if (strchCount.empty()) 
       {
			strchCount += '\n';
			ReadLine(fIn, strchCount);
		}

    //因为数据的格式是 A:3,记录读取到的相关字符信息方便构建哈夫曼树,
		_fileInfo[(unsigned char)strchCount[0]]._count = atoi(strchCount.c_str() + 2);
	}

注意:

  • それは、新しい行の中で成功せず、抜け出すラップバッファに読み込まれ、私たちのパッケージのreadline機能が検出されたため、複数の行(すなわち、男性ラップ)を含むファイルは、あなたが、彼のパーティー後に再度読み込む必要がある場合、それはする必要があるif (strchCount.empty())裁判官如果没有读取到任何字符,就代表读取到了换行符、 strchCountに追加改行を入れて、その後、改行の出現数を得るために、1行下に読んで

V.の復興HU FF男ツリー

HuffmanTree<CharInfo> t;
	t.CreateHuffmanTree(_fileInfo, CharInfo(0));//构建哈夫曼树

VI。解凍

//解压缩后的文件名
	std::string newFileName = "3" + strFilePostFix;

	FILE* fOut = fopen(newFileName.c_str(), "wb");
  if(fOut == nullptr)
  {
    perror("open file is error\n");
    return ;
  }

	char *pReadBuff = new char[1024];
	char ch = 0;
	HuffmanTreeNode<CharInfo>* pCur = t.GetRoot();//拿到根节点,也就拿到了整个哈夫曼树的权值之和
	size_t fileSize = pCur->_Weight._count;//记录待解压的总字节数
	size_t unCount = 0;//记录已经解压字符的个数
	while (1) 
  {
		size_t rdsize = fread(pReadBuff, 1, 1024, fIn);
		if (rdsize == 0) 
    {
			break;
		}
    
		for (size_t i = 0; i < rdsize; ++i) 
    {
			ch = pReadBuff[i];
			for (int pos = 0; pos < 8; ++pos) 
      {
        //0x80--->1000 0000 所以是用来判断一个字节的高位是1还是0的
        //规定 1--->往哈夫曼树的右子树走  0--->往哈夫曼树的左子树走
				if (ch & 0x80) 
        		{
					pCur = pCur->_pRight;
				}
				else 
        		{
					pCur = pCur->_pLeft;
				}

				ch <<= 1;

        //如果pCur左右孩子都为空,说明走到叶子节点了,就可以获取到具体的字符了
				if (nullptr == pCur->_pLeft && nullptr == pCur->_pRight) 
       			{
					++unCount;
					fputc(pCur->_Weight._ch, fOut);
					pCur = t.GetRoot();

          //因为每次不一定刚好是整字节数,所以防止多读,需要进行判断
					if (unCount == fileSize)
						break;

				}
			}
		}

注意:

  • 1つの規定は右、0を左ゴーゴー時間は、彼が間にファイルを解凍するために書かれた文字を解凍したリーフノードを、来たときに、
  • 文字情報は、バイトでメモリのバイトに格納されている場合、その8bite、そのため私たちは、それぞれ一口ビットが0または1であることがわかっている場合、あなたはまだ最後の方に行かなければならない、ハフマンが行くために残されているかを制御することができます文字情報を取得するリーフノードに行ってきました、我々ので、&0x80を(0000 1000) 結果は、ビットが1である真かまの代表的なものであるならば、それ以外の場合は、あなたがトレンドを制御することができるように、0であります
  • 最後に、最後の1ビットの行き過ぎの解凍を防ぐ、ファイル全体のサイズへの情報の値に基づいて、右ハフマンルート・ノードを取得するには、それぞれが正常に右++ unCountに、データを抽出した後、最終的にunCountとファイルサイズの大きさを決めますそれは解凍の代わりに等しい場合、すべての出ている、それに続くビットは、圧縮されたデータをビットではありません
  • これまで、ほとんどの最終再びすることにより、保存文字情報は、関連する変数unisigned char型を使用するには、char型は使用できません。圧縮や解凍時にそれ以外の場合は、文字が文句を言うでしょう
  • テキストファイルフラグの端部は、EOF(-1)であり、圧縮ファイルの結果は、FF(すなわち、11111111 ...、32 1)の場合に可能なテキストファイルで F E ザ・ F (もし!EOF()) 、それが予期せず終了する際に決定し、ファイルを読み書きする必要があるバイナリやり方で

解凍完整代码

//解压缩
void FileCompressHuffman::UnCompressFile(const std::string& path) {
	FILE* fIn = fopen(path.c_str(), "rb");
	if (nullptr == fIn) {
		//assert(false);
    perror("open file is error");
		return;
	}

  //文件后缀
	std::string strFilePostFix;
	ReadLine(fIn, strFilePostFix);

  //读取文件数据的行数
	std::string strCount;
	ReadLine(fIn, strCount);

	int lineCount = atoi(strCount.c_str());
	for (int i = 0; i < lineCount; ++i) 
  {
    //记录读取每一行的数据
		std::string strchCount;
		ReadLine(fIn, strchCount);

    //如果读到的数据为空,说明可能读到了换行符
		if (strchCount.empty()) 
    {
			strchCount += '\n';
			ReadLine(fIn, strchCount);
		}

    //因为数据的格式是 A:3,记录读取到的相关字符信息方便构建哈夫曼树,
		_fileInfo[(unsigned char)strchCount[0]]._count = atoi(strchCount.c_str() + 2);
	}

	HuffmanTree<CharInfo> t;
	t.CreateHuffmanTree(_fileInfo, CharInfo(0));//构建哈夫曼树

  //解压缩后的文件名
	std::string newFileName = "3" + strFilePostFix;

	FILE* fOut = fopen(newFileName.c_str(), "wb");
  if(fOut == nullptr)
  {
    perror("open file is error\n");
    return ;
  }

	char *pReadBuff = new char[1024];
	char ch = 0;
	HuffmanTreeNode<CharInfo>* pCur = t.GetRoot();//拿到根节点,也就拿到了整个哈夫曼树的权值之和
	size_t fileSize = pCur->_Weight._count;//记录待解压的总字节数
	size_t unCount = 0;//记录已经解压字符的个数
	while (1) 
  {
		size_t rdsize = fread(pReadBuff, 1, 1024, fIn);
		if (rdsize == 0) 
    {
			break;
		}
    
		for (size_t i = 0; i < rdsize; ++i) 
    {
			ch = pReadBuff[i];
			for (int pos = 0; pos < 8; ++pos) 
      {
        //0x80--->1000 0000 所以是用来判断一个字节的高位是1还是0的
        //规定 1--->往哈夫曼树的右子树走  0--->往哈夫曼树的左子树走
				if (ch & 0x80) 
        {
					pCur = pCur->_pRight;
				}
				else 
        {
					pCur = pCur->_pLeft;
				}

				ch <<= 1;

        //如果pCur左右孩子都为空,说明走到叶子节点了,就可以获取到具体的字符了
				if (nullptr == pCur->_pLeft&&nullptr == pCur->_pRight) 
        {
					++unCount;
					fputc(pCur->_Weight._ch, fOut);
					pCur = t.GetRoot();

          //因为每次不一定刚好是整字节数,所以防止多读,需要进行判断
					if (unCount == fileSize)
						break;

				}
			}
		}

	}
	fclose(fIn);
	fclose(fOut);
	delete[] pReadBuff;
}

ハフマン圧縮の問題に基づいて、まだ存在しています:

  • 画面を圧縮することができない、画像、オーディオファイルは、テキストファイル、圧縮されたビデオ、写真、その他のファイルや他の圧縮ファイルが大きいでしょう圧縮することができます
公開された126元の記事 ウォン称賛57 ビュー90000 +

おすすめ

転載: blog.csdn.net/wolfGuiDao/article/details/104758855