RLE压缩解压算法的完整实现

和第四题一样同样是各种东拼西凑的结果,希望对一部分人有帮助。要用的话请至少改一下变量名和函数顺序并且搞懂为什么,不要直接抄袭。在此感谢陈德创大佬的无私帮助以及陈万庆老师提供的音频测试文件
看之前请先搞懂RLE算法的原理和部分代码实现
RLE算法原理及C语言实现

原题:

涉及知识点:文件读写、位操作、内存管理、结构体定义、RLW算法、命令行参数

要求:

编写一个程序,可以在命令行输入参数,完成指定文件的压缩解压

命令行参数如下

rle file1 –c(-d) file2

第一个参数为可执行程序名称,第二个参数为原始文件名,第三个参数为压缩或解压缩选项,第四个参数为新文件名

问题分析

题目已经提示了要求用RLE算法结合位运算来实现解压缩,经过思考可以知道所有文件的本质都是二进制文件,这道题需要通过位操作和RLE算法直接压缩二进制代码。现在的问题有:

1.什么是RLE算法?如何用C语言实现RLE算法?

2.如何按照二进制的方式分块读入文件并在文件压缩和解压缩后输出?

解决方案(思路)

RLE算法的本质在于区分连续字节块和非连续字节块,用单独的字节来存储连续字节块和非连续字节块关的长度。对于其原理和代码实现,我在阅读了文档后自己进行了整理并写了一篇博客,链接如下。由于报告的篇幅原因就没有把全文内容附在报告内,后面的内容会直接引用博客中的概念和代码。

https://blog.csdn.net/zimuzi2019/article/details/106583064

对于单个文件,传入文件后通过文件指针每次读入一定数量的字节数据,这些字节数据传入函数进行压缩编码或者解压解码后再把新数据写入指定的新文件

算法分析

根据输入的命令行参数进行对应操作

  • 若为压缩操作则将指定要压缩的文件名和要输出的文件名传入Compression函数,分别创建两个文件指针指向输入和输出文件,两个申请的内存空间中inbuf用于存储待压缩的数据块,outbuf用于存储待输出的数据块。然后用fread函数每次读入定长的字节数,并用length记录成功读入的字节数。把读取的字节数length,指向两块申请的内存空间inbuf和outbuf,存储待输出数据块的数组outbuf的大小传入RLe_Encode函数进行压缩编码。在RLe_Encode函数内建立输入指针src指向inbuf。循环遍历inbuf数组直到inbuf剩余字节为0。循环时用IsrepetitionStart函数判断,若连续的三个字节数据相同时则利用GetRepetitionCount函数得到重复的个数并将连续字节块和记录连续字节块的字节写入输出数组outbuf同时移动数组指针。否则利用GetNonRepetitionCount函数得到不重复的个数并逐个写入outbuf数组。

  • 若为解压缩操作则将指定要解压的文件名和要输出的文件名传入Decompression函数,分别创建两个文件指针指向输入和输出文件。两个申请的内存空间中inbuf用于存储待解压缩的字节块,outbuf用于存储待输出的字节块。然后用fread函数每次读入定长的字节数,并用length记录成功读入的字节数。把读取的字节数length,指向两块申请的内存空间inbuf和outbuf,存储待输出数据块的数组outbuf的大小传入RLe_Decode函数进行解压缩解码。在RLe_Decode函数内建立输入指针src指向inbuf,循环遍历inbuf数组,若发现连续重复标记则则将标识字节后面的数据重复复制n份写入outbuf。否则说明是非连续数据,将标识字节后面的n个数据复制到outbuf。n值由存储长度信息的字节块的值确定。

源代码:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int IsrepetitionStart(unsigned char *src,int srcLeft){
    if(srcLeft<3){
        return 0;
    }
    if((src[0]==src[1])&&(src[1]==src[2])){
        return 1;
    }
    return 0;
}

int  GetRepetitionCount(unsigned char *src,int srcLeft){
    int repeatedbuf=src[0];
    int length=1;
    while(length<srcLeft&&length<0x7f&&src[length]==repeatedbuf){
        length++;
    }
    return length;
}

int GetNonRepetitionCount(unsigned char *src,int srcLeft){
    if(srcLeft<3){
        return srcLeft;
    }
    int length=2;
    int a=src[0],b=src[1];
    while(length<srcLeft&&length<0x7f&&((a!=b)||(b!=src[length]))){
        a=b;
        b=src[length];
        length++;
    }
    return length;
}

int Rle_Encode(unsigned char *inbuf,int inSize,unsigned char *outbuf,int onuBufSize)
{
    unsigned char *src=inbuf; 
    int i;
    int encSize=0;
    int srcLeft=inSize;       
    while(srcLeft>0){         
        int count=0;
        if(IsrepetitionStart(src,srcLeft)){ 
            if((encSize+2)>onuBufSize){      
                return -1;
            } 
            count=GetRepetitionCount(src,srcLeft); 
            outbuf[encSize++]=count|0x80;          
            outbuf[encSize++]=*src;             
            src+=count;                            
            srcLeft-=count;
        }else{
            count=GetNonRepetitionCount(src,srcLeft); 
            if((encSize+count+1)>onuBufSize){ 
                return -1;
            }
            outbuf[encSize++]=count;
            for(i=0;i<count;i++){           
                outbuf[encSize++]=*src++;
            }
            srcLeft-=count;
        }
    }
    return encSize;
}

int Rle_Decode(unsigned char *inbuf,int inSize,unsigned char *outbuf,int onuBufSize){
    unsigned char *src=inbuf;
    int i;
    int decSize=0;
    int count=0;
    while(src<(inbuf+inSize)){
        unsigned char sign=*src++;
        int count=sign & 0x7F;
        if((decSize+count)>onuBufSize){ 
            return -1;
        }
        if((sign&0x80)==0x80){          
            for(i=0;i<count;i++){
                outbuf[decSize++]=*src;
            }
            src++;
        }else{
            for(i=0;i<count;i++){
                outbuf[decSize++]=*src++;
            }
        }           
    }
    return decSize;
}

int Compression(char*Inputfilename,char*Outputfilename){
    FILE *Input=fopen(Inputfilename, "rb");
    FILE *Output=fopen(Outputfilename, "wb");
    if (Input==NULL||Output==NULL){
         printf("We can't open the file successfully!");
    }
    unsigned char*inbuf;
    unsigned char*outbuf;
    inbuf =(unsigned char*)malloc((sizeof(unsigned char))*1024*1024*1024);
    outbuf=(unsigned char*)malloc((sizeof(unsigned char))*1024*1024*1024);
    int length;
    while ((length=fread(inbuf, sizeof(unsigned char),1024,Input))!= 0){
            int tmp=Rle_Encode(inbuf,length,outbuf,1024*1024*1024);
            if(tmp==-1){
                return -2;
            }
            fwrite(outbuf, sizeof(unsigned char),tmp,Output);
    }
    fclose(Input);
    fclose(Output);
}

int Decompression(char*Inputfilename,char*Outputfilename){
    FILE *Input=fopen(Inputfilename, "rb");
    FILE *Output=fopen(Outputfilename, "wb");
    if (Input==NULL||Output==NULL){
         printf("We can't open the file successfully!");
    }
    unsigned char*inbuf;
    unsigned char*outbuf;
    inbuf =(unsigned char*)malloc((sizeof(unsigned char))*1024*1024*1024);
    outbuf=(unsigned char*)malloc((sizeof(unsigned char))*1024*1024*1024);
    int length;
    while((length=fread(inbuf, sizeof(unsigned char),1024*1024*1024,Input))!=0){
            int tmp=Rle_Decode(inbuf,length,outbuf,1024*1024*1024);
            if(tmp==-1){
                return -2;
            }
            fwrite(outbuf, sizeof(unsigned char),tmp,Output);
    }
    fclose(Input);
    fclose(Output);
}

int main(int argc,char**argv)
{
    if(strcmp(argv[2],"-c")==0){
       Compression(argv[1],argv[3]);
    }else if(strcmp(argv[2],"-d")==0){
       Decompression(argv[1],argv[3]);
    }  
    return 0;
}

测试数据(输入,输出):

压缩txt文本文件

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

压缩bmp图形文件

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

压缩mp3音频文件(感想陈万庆老师提供的英语听力测试文件!)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
尝试播放后会发现解压的音频可以正常播放(我听过一遍,确实一样,嗯),和原内容一样
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/zimuzi2019/article/details/106721704