C/C++程序设计—RLE简单算法
RLE算法压缩、解压文件(初级)
1.RLE概述
RLE(Run Length Encoding行程编码)算法是一个简单高效的无损数据压缩算法。
其基本思路是把数据看成一个线性序列,而这些数据序列组织方式分成两种情况:一种是连续的重复数据块,另一种是连续的不重复数据块。对于连续的重复数据块采用的压缩策略是用一个字节(我们称之为数据重数属性)表示数据块重复的次数,然后在这个数据重数属性字节后面存储对应的数据字节本身。
例如某一个文件有如下的数据序列AAAAA,在未压缩之前占用5个字节,而如果使用了压缩之后就变成了5A,只占用两个字节,对于连续不重复的数据序列,表示方法和连续的重复数据块序列的表示方法一样,只不过前面的数据重数属性字节的内容为1。
2、压缩分析:
了解了最基本的RLE算法后,压缩一个文件无非就是将重复的字节用一对数据来表示,即一个数据块[block],它为两个字节,第一个字节为个数,第二个字节为内容。从而将文件变成很多个这样的块,(这对重复程度大的文件来说有较为理想的压缩效果,而内容像ABCABCABC的话使用这种算法文件会增大,就是1A1B1C1A1B1C1A1B1C了,更长,就达不到压缩的效果了,此处只讨论最基本的算法。)
3、解压分析:
由以上可知,源文件被压缩成了n个 [block]块,解压的过程就是将这些块一个一个释放出来即可,并写入新文件中。(第一个字节为写入的个数,第二个字节为写入的内容)。
4、运行实例:
演示:
如图,一个文件夹123.txt内容如下:
操作程序:
new.txt如下:
进行解压:
打开解压后的文件:
成功!
注:仅为最简单的RLE算法未做改进,如有不当之处,还请批评指正!
源代码如下:
#include<iostream>
using namespace std;
void compress(const char* src, const char* dest)//压缩
{
FILE* fr = fopen(src, "rb");//二进制读取
FILE* fw = fopen(dest, "wb");//二进制写入
if (NULL == fr)
{
cout << "wrong!";
return;
}
int count = 0;//记录相同字节的个数
char samechar;//记录相同字节的内容
char temp = fgetc(fr);//先获取第一个字节
samechar = temp;
while (temp !=EOF)
{
if (temp == samechar)
{
count++;//每当下一个字节与标志字节相同时,计数加一,并读取下一个字节
temp = fgetc(fr);
continue;
}
else//否则,写入文件,每一块有两个字节
{
fwrite(&count, 1, 1, fw);//保存个数
fwrite(&samechar, 1, 1, fw);//保存内容
//初始化标志字符和计数器
samechar = temp;
count = 0;
}
}
//将文件结尾的一个或多个字节压缩至新文件
if (count > 0)
{
fwrite(&count, 1, 1, fw);
fwrite(&samechar, 1, 1, fw);
}
//关闭流
fclose(fr);
fclose(fw);
cout << "压缩完成!";
}
void decompress(const char* src, const char* dest)//解压
{
FILE* fr = fopen(src, "rb");
FILE* fw = fopen(dest, "wb");
if (NULL == fr)
{
cout << "wrong!";
return;
}
char temp;
int count;
//解压很简单,每两个字节为一对,第一个为个数,第二个为内容
while ((count = fgetc(fr)) != EOF)
{
temp = fgetc(fr);
for (int i = 0; i < count; i++)
{
fwrite(&temp, 1, 1, fw);
}
}
cout << "解压成功!";
fclose(fr);
fclose(fw);
}
int main()
{
//用命令行来操作程序
char src[100];
char dest[100];
char method='1';
cout << "请输入命令:\n格式:rle file1 -c(-d) file2\n -c/-d代表压缩、解压\n";
scanf("rle %s -%c %s", &src, &method, &dest);
if (method == 'c')
{
compress(src, dest);
}
else if (method == 'd')
{
decompress(src, dest);
}
else
{
cout << "输入错误!\n"<<endl;
}
}