LZ77アルゴリズムとファイルベースのハフマン圧縮アルゴリズム(7)
ファイル圧縮とLZ77アルゴリズム(VI)に基づいて、ハフマンアルゴリズムは、ファイル圧縮の過程を説明するために完了した、解凍ファイルは、この記事では、プロセスや大きなファイルの取扱いについて説明し
まず、伸長処理
LZ77圧縮ソリューションは非常に簡単です:
- タグは、ファイル1から読み出され、分析されたマーカー
- このフラグが0である場合は、元の文字を表し、バイトは解凍後に直接書き込まれたファイル2、ファイルから読み込まれます
- このフラグが1の場合、遭遇する(距離、長さ)を表し、ファイル3からの2バイトの読み出しは、距離を表し、ファイルのバイト長から読み出され、ビルド(距離、長さ)対、その後、圧縮された結果ソリューションから一致長を見つけます
- 次のマーク、すべての完成までに解決マークを取得します。
第二に、マージフラグ情報ファイルと圧縮されたデータファイル
- 私たちは、スタート前に解凍する必要が圧縮されたデータファイルやタグ情報ファイルをマージ、その後一緒にマージされ、圧縮されたデータとタグ情報とそれを区別するためにどのように?
- 私たちは、間のマージされたファイル圧縮を持っています
写入标记信息的总字节数和原数据文件的大小
。
- 合併完了後のことに注意してください
文件大小和标记信息大小的 获取方式
:
//获取源文件大小
ULL fileSize = 0;
fseek(fInF, 0 - sizeof(fileSize), SEEK_END);
fread(&fileSize, sizeof(fileSize), 1, fInF);
//获取标记信息的大小
size_t flagSize = 0;
fseek(fInF, 0 - sizeof(fileSize) - sizeof(flagSize), SEEK_END);
fread(&flagSize, sizeof(flagSize), 1, fInF);
合并文件
//合并文件
void LZ77::MergeFile(FILE* fOut, ULL fileSize)
{
//将压缩数据文件和标记信息文件合并
//1.读取标记信息文件中内容,然后将结果写入到压缩文件中
FILE* fInf = fopen("3.txt", "rb");
size_t flagSize = 0;
UCH* pReadbuff = new UCH[1024];
while (true)
{
size_t rdSize = fread(pReadbuff, 1, 1024, fInf);
if (rdSize == 0)
break;
//把标记信息写到压缩数据文件中
fwrite(pReadbuff, 1, rdSize, fOut);
//更新数据
flagSize += rdSize;
}
//向压缩数据文件中写标记信息大小,方便解压缩
fwrite(&flagSize, sizeof(flagSize), 1, fOut);
//向压缩数据文件中写文件数据大小,方便解压缩
fwrite(&fileSize, sizeof(fileSize), 1, fOut);
delete[] pReadbuff;
fclose(fInf);
}
- ご注意ください
读取标记信息文件指针的起始位置
//将读取标记信息的文件指针移动到保存标记数据的起始位置
fseek(fInF, 0 - sizeof(flagSize) - sizeof(fileSize) - flagSize, SEEK_END);
-
合併後、解凍プロセス:
3の減圧開始 -
タグファイル(01ビット文字または元の距離の長さを示す8ビット)chFlagバイトを読み取る最初もあり、
& 0x80来判断高位01情况
-
フラグ情報が1である場合、それは、距離の長さを表すことに留意されたいです
长度读取出来需要 + 3
。 -
距離情報の長さである場合、再度それから、ファイルポインタを必要とする
解压缩文件末尾往前偏移距离个位置
(すなわち、開始文字と一致するように配置しました)然后往后写长度个字符到解压缩文件
-
メモメモ書き込ま読み取り効率を向上させるためにオペレーティング・システムが、さ
提供缓冲区的机制
、如果你向文件当中写入数据,其实是写到缓冲区当中,缓冲区满就才会往文件当中写
つつ、先ほど述べた、解凍ファイルは圧縮されたデータが書き込まれる二つのポインタ(で開かれ、マッチング文字開始位置を特定することです)、现在如果写压缩数据的文件指针把数据写入到缓冲区并没有写入到文件,此时定位匹配字符开始位置的指针需要读取长度个字符写入到解压缩文件,
データが圧縮されたファイルバッファ間でまだあるので、これは、エラーになり、圧縮されたファイルの代わりにデータのどれもが、あなたは解凍目的を達する、あなただけの255を読み取ることができ、読み取りに行くん。どのようにそれを解決するには???リフレッシュバッファ
解压缩完整代码
:
//解压缩
void LZ77::UNCompressFile(const std::string& strFilePath)
{
//打开压缩文件和标记文件
FILE* fInD = fopen(strFilePath.c_str(), "rb");
if (nullptr == fInD)
{
std::cout << "压缩文件打开失败" << std::endl;
return;
}
//操作标记数据的文件指针
FILE* fInF = fopen(strFilePath.c_str(), "rb");
if (nullptr == fInF)
{
std::cout << "压缩文件打开失败" << std::endl;
return;
}
//获取源文件大小
ULL fileSize = 0;
fseek(fInF, 0 - sizeof(fileSize), SEEK_END);
fread(&fileSize, sizeof(fileSize), 1, fInF);
//获取标记信息的大小
size_t flagSize = 0;
fseek(fInF, 0 - sizeof(fileSize) - sizeof(flagSize), SEEK_END);
fread(&flagSize, sizeof(flagSize), 1, fInF);
//将读取标记信息的文件指针移动到保存标记数据的起始位置
fseek(fInF, 0 - sizeof(flagSize) - sizeof(fileSize) - flagSize, SEEK_END);
//开始解压缩
//写解压缩数据
//FILE* ffOut = fopen("5.txt","rb");
//std::string filestr ;
//std::cout<<filestr<<std::endl;
//fread(&filestr,sizeof(filestr),1,ffOut);
//std::string str = "4.";
//str += filestr;
//fclose(ffOut);
FILE* fOut = fopen("4.txt", "wb");
assert(fOut);
FILE* fR = fopen("4.txt", "rb");
assert(fR);
UCH bitCount = 0;
UCH chFlag = 0;
ULL encodeCount = 0;//标记已经解压缩的数据大小,方便判断解压缩的结束
while (encodeCount < fileSize)
{
//读取标记
if (0 == bitCount)
{
//读取一个字节
chFlag=fgetc(fInF);
bitCount = 8;
}
if (chFlag & 0x80)//当前字节的高位为1
{
//距离长度对
USH matchLen = fgetc(fInD) + 3;//长度
USH matchDist = 0;//距离
fread(&matchDist, sizeof(matchDist), 1, fInD);
//清空缓冲区,非常重要
fflush(fOut);
//更新已经解码的字节数大小
encodeCount += matchLen;
//fR:读取前文匹配串中的内容
UCH ch;
fseek(fR, 0 - matchDist, SEEK_END);
while (matchLen)
{
ch = fgetc(fR);
fputc(ch, fOut);
--matchLen;
//在还原长度距离对时,一定要清空缓冲区,否则可能会还原出错
fflush(fOut);
}
}
else
{
//原字符
UCH ch = fgetc(fInD);
fputc(ch, fOut);
encodeCount += 1;
}
chFlag <<= 1;
bitCount--;
}
fclose(fInD);
fclose(fInF);
fclose(fOut);
fclose(fR);
}
ここでは、単純にファイルを抽出することは、単に次のためにOK、となっている大文件的压缩和解压缩
サプリメント
第四に、サイズの大きいファイルの処理
- 更新ハッシュテーブル:左のウィンドウに右のウィンドウ間でデータを移動し、上書きされたままにされたデータウィンドウは、データが右側のウィンドウにすでにある場合は起動している - WSIZEの場所を、ハッシュテーブルを更新する必要があるので、
//更新哈希表
void HashTable::Update()
{
for (USH i = 0; i < WSIZE; ++i)
{
//先更新head,把大于等于WSIXE的下标 减去 WSIZE 放到哈希表的左窗内
//把head中小于WSIZE 的下标直接置为0,因为小于WSIZE的下标
//在查找缓冲区中距离先行缓冲区的距离太远了,进行匹配不划算
if (head_[i] >= WSIZE)
head_[i] -= WSIZE;
else
head_[i] = 0;
//更新prev,和head同理
if (prev_[i] >= WSIZE)
prev_[i] -= WSIZE;
else
prev_[i] = 0;
}
}
窓を埋める2.
- ウィンドウを右に再びデータを記入した場合、ソースファイルが小さいファイルの場合であることに注意してください、その後、圧縮された部分は、データソースファイルを持っていない、ファイルポインタは、ファイルの終わりに達した、エラーが裁判官にする必要があります
//向缓冲区中填充数据
void LZ77::FillWindow(FILE* fIn, size_t& lookAhead, USH& start)
{
//start压缩已经进行到右窗,先行缓冲区剩余数据不够MIN_LOOKAHEAD
if (start >= WSIZE) //如果不进行if判断,在进行小文件压缩时还会继续
//从文件中读取数据,但是文件已经走到末尾
{
//1.将右窗中的数据搬移到左窗
memcpy(pWin_, pWin_ + WSIZE, WSIZE);
//将右窗中的内容清0,防止影响后续数据
memset(pWin_ + WSIZE, 0, WSIZE);
//更新start,start本来是大于WSIZE,经过1步骤后,start应该在左窗,
start -= WSIZEc;
//2.更新哈希表
ht_.Update();
//3.向右窗中补充WSIZE个的待压缩数据
if (!feof(fIn))//判断文件是否走到末尾
lookAhead += fread(pWin_ + WSIZE, 1, WSIZE, fIn);
}
}
3.なお、重複範囲のルックと圧縮
- 文字列マッチングの長さは、距離は何時にポインタがチャートBDを行ってきました。このシナリオの下では?
(5,3)
为什么指针在E4的时候不进行匹配呢
?それは試合を行うことができることを理由に立っています。我々は0に設定されたハッシュテーブルの各位置を初期化するときに答えは、ハッシュテーブルの構造に起因している鎖の末端に達してマッチ、E4 BD A0を介してハッシュ関数計算の終了と一致する手段ハッシュされたアドレス、ハッシュアドレスを対応する位置にバッファの間で、このリリースE4の下付き文字、これはちょうど別のインデックス0になった後、E4の到着後の第二は、マッチヘッドが、0になってしまいますそう一致させることはありません
- この場合、必要な長さの減少は、よりリフレッシュバッファ、あなたはここで二回リフレッシュバッファを解凍する必要があります
ここでは、ファイル圧縮アルゴリズムLZ77に基づいて完成されています
V.の概要
私たちのプロジェクトは、アイデアのGZIP圧縮をベースにしています。
1.概要GZIP圧縮の考え
2.不良品
- 提示完成ファイルベースのハフマンとLZ77圧縮および伸張アルゴリズムを。
改进的方向就是把Huffman和LZ77算法的文件压缩与解压缩结合起来,模拟GZIP
- しかし、圧縮率が理想的ではありませんので、直接ではなく、LZ77の圧縮の結果は、ハフマン符号で圧縮しました
プロジェクトの3の改善の方向
- 直接圧縮法ハフマン木-----修正ハフマン木のないLZ77圧縮結果の操作を行います。
范式Huffman树
4.パラダイムハフマン木は、
次のセクションを参照してください。