自制压缩软件

结构

压缩软件的核心在于压缩算法。基于Huffman编码的压缩算法思路:

  1. 二进制方式读取源文件,按照每8bits作为一个字符;
  2. 统计每个字符的出现频率即为叶子结点的权值,按照Huffman算法得到每个叶子的编码;
  3. 对源文件的每个字符,将新的编码组合为二进制流,按照每8bits一个单位写入压缩文件。

举例来看:
假设我们有待压缩源文件helloh的ASCII码为01101000,同理可得整个文件的二进制形式0110100001100101011011000110110001101111,共5B,40bits。
根据Huffman算法:得到h的编码为00,同理可得整个文件的Huffman编码为0001111110,末尾不够8bits,采用补0的方法可得0001111110000000,按照每8bits一个单位,写入压缩文件的是31255对应的字符,共2B,16bits。
解压缩流程是压缩的逆过程:

  1. 二进制方式读取压缩文件;
  2. 每次取1bit,从Huffman树的根结点出发,找到某个叶子即为源字符。

效果

做一个简单的比较:

压缩软件 测试文件 压缩率 测试文件 压缩率
CompressIt txt(840B) 70.4% png(282KB) 101%
WinRaR txt(840B) 14.4% png(282KB) 100%

压缩率和压缩时间和专业软件没法比。之所以出现压缩文件大于源文件,是因为压缩文件中还存储了Huffman树等信息,为解压所需。
对于不同内容的文件,得到的压缩文件大小也不尽相同,这主要与Huffman编码的性质有关。

理论分析

Huffman编码依赖于信源的统计特征,其背后的原理在于为出现频率高的字符分配尽可能短的码长,这样就可以降低平均码长:
\[L=\Sigma p_il_i\]
使得\(L\)最短的编码就是最优编码,可以证明Huffman编码是一种最优编码。
同时Huffman编码还是前缀码,简化了解码过程。
假设一种理想情况:源文件长\(len\)很大,共有\(m\)种不同字符,每个字符用8bits表示,并且每种字符出现频率\(\frac{len}{m}\)相同,忽略掉存储Huffman树等信息所需的空间。
这棵完全二叉树共有结点\(n=2*m-1\)个,那么树深度为\(h=1+\lfloor log_2n \rfloor\),每个字符的压缩长度为\(h-1=\lfloor log_2n \rfloor\),故压缩后的串长度为\(\frac{(h-1)*len}{8}\),可得压缩率\(\frac{h-1}{8}\),即:
\[\alpha=\frac{\lfloor log_2(2*m-1) \rfloor}{8}\]
源文件中不同字符种类\(m\)越小,即源文件分布越集中,压缩效果越好。
如果和定长编码比较,可以得到压缩率:
\[\alpha=\frac{\lfloor log_2(2*m-1) \rfloor}{\lceil log_2(m) \rceil}\]
\(m\)取值256时,Huffman树是一棵满二叉树,压缩率为100%,并不比8位固定长度编码更高效。

收获

  • EOFfeof()
    EOF是一个定义在cstdio头文件中的宏,一般为-1:
#define EOF (-1)

但是如果按照二进制读取文件,对于文件中的-1又该如何处理?
阮一峰的博客说:

在Linux系统之中,EOF根本不是一个字符,而是当系统读取到文件结尾,所返回的一个信号值(也就是-1)。至于系统怎么知道文件的结尾,资料上说是通过比较文件的长度。

我们通常会写出下面程序来读取文件:

int ch;
while ((ch = fgetc(fp)) != EOF) {
    // your code here
}

但是fgetc()在到达文件结尾和发生读取错误的情况下都会返回EOF,所以上述代码不严谨,采用feof()函数来判断文件结尾:

int ch;
while (!feof(fp)) {
    ch = fgetc(fp);
    // your code here
}

但是采用feof()也有一个问题:读取最后一个字符后,feof()仍然返回0,进入循环,fgetc()再向后读取一个字符,feof()才返回1,这样程序会多循环一次。
所以比较安全的写法是:

int ch = fgetc(fp);
while (ch != EOF) {
    // your code here
    ch = fgetc(fp);
}
if (feof(fp))
    puts("End-of-File reached.");
else
    puts("Something went wrong.");
  • 虚析构函数
    基类的析构函数一般写成虚函数,做个测试:
class base {
public:
    base() {};
    virtual ~base() {
        cout << "destructor in base" << endl;
    };

    virtual void f() {
        cout << "f in base" << endl;
    }
};

class derive :public base {
public:
    derive() {};
    ~derive() {
        cout << "destructor in derive" << endl;
    };

    void f() {
        cout << "f in derive" << endl;
    }
};

base* p = new derive;
p->f();
delete p;

输出:

f in derive
destructor in derive
destructor in base

如果基类的析构函数不是虚函数,输出:

f in derive
destructor in base

结果并没有调用派生类的析构函数,造成内存泄漏。
所以基类的虚析构函数的作用是:当一个基类指针删除一个派生类对象,确保调用派生类的析构函数

  • 二进制文件
    在压缩过程中,对于不同格式源文件的读取都是采用二进制方式rb
    实际上二进制文件和文本文件并没有本质区别,你所看到的内容取决于打开文件的软件对二进制流的解释方式,文件扩展名帮助计算机知道应该用哪种解释方式,通常的文本文件的解释方式有ASCII码和Unicode码。

原文地址:https://www.cnblogs.com/EIMadrigal/p/12275558.html

时间: 2024-10-29 12:18:46

自制压缩软件的相关文章

德国精品软件推荐 &nbsp; 压缩软件 WINRAR 个人版终于免费了。

以下为WinRAR 致用户的一封信 (宣布个人免费版) 我们很荣幸地宣布,经过15年多的时间,现在终于向中国的个人用户提供一款完全免费的 WinRAR 简体中文版了.这是因为 WinRAR 的全球独家发行商 win.rar GmbH 和 www.winrar.com.cn 希望藉此来感谢数亿中国用户长久以来对 WinRAR的信任. 许多公司曾试图复制类似 WinRAR的产品,但是我们的用户始终相信我们并坚持使用原版软件,即使这意味着不得不在同一台计算机上运行两种压缩工具.随着全新的 WinRAR

iOS开发中,PNG图片的各种压缩软件,以及压缩率对比

各种压缩软件的对比情况: http://jamiemason.github.io/ImageOptim-CLI/comparison/png/photoshop/desc/ 压缩率较高的为 ImageAlpha的有损压缩 加上 ImageOptim的无损压缩,二者要要先后顺序, 嫌麻烦的话,少量图片也可以使用在线工具:TinyPNG 此工具有api,但是有限制,每个key每月300次,再多就要收费 ImageOptim 进入官网 无损压缩,GUI + Command Line(有GUI软件,也有

压缩软件命令行

前言 说到压缩文件,我们可以通过编程的方式来写压缩代码,但是考虑到时间问题,我们可以调用压缩软件提供的命令行功能,快速实现某些功能的自动化. 以国产压缩软件 好压 为例 好压命令行帮助:http://haozip.2345.com/help/help11-1.htm Win10步骤 (说明:家里电脑系统是windows 10 x64企业版,无法通过配置环境变量的方式来直接调用HaoZipC,所以通过此方法) 创建一个bat文件,输入如下内容:说明:这个bat是把xx_xx目录下所有文件压缩到xx

实训之压缩软件

# 压缩文件 import tkinterimport tkinter.filedialogimport tkinter.messageboximport zipfileimport os class ZipDemo: def __init__(self): self.root = tkinter.Tk() self.root.minsize(300, 400) self.root.title('chy压缩软件') self.showLabel() self.root.mainloop() se

电脑小白学习第六课---打包压缩软件WINRAR

有时为了便于通过网络传输文件,或者为了节省存储空间,我们可以使用压缩软件进行压缩打包操作.压缩软件有很多.比较常用的是winrar.7zip.好压等.我们以winrar为例介绍一下.首先下载安装winrar.下载后,双击安装包,开始安装.直接确定,完成安装.下面对需要压缩打包的文件或文件夹操作.1.压缩打包选中需要处理的文件或文件夹,在选中的上面右击选择"添加到"temp.rar"",这里的temp是上一层目录的文件夹名称.生成压缩文件,如下图所示.如果想对打包压缩

360压缩|360压缩软件下载

每次下个压缩文件.都会弹出一个对话框..然后**一大堆..然后就叫我安装360压缩,他喵的还没有取消,只有确定.点完确定还不能退出.一下就给你装好,还是C盘.每次都得去卸载.360杀毒我是用惯了,可是我真心不想用360压缩啊..360压缩下载链接360压缩软件是360公司的一个免费的压缩软件.在压缩的速度是绝对是比快winrar.7-zip,要快的.而且360可以支持压缩24种总格式,最厉害的是360压缩软件内置云安全引擎,可以直接在压缩文件中是否有没有病毒可以让你的电脑变的更加安全.360压缩

用Python写一个带图形界面的文件压缩软件

文件压缩和解压我们在日常工作学习中会经常用到,比如winrar.快压.好压等压缩软件 打开之后的界面长这个样子: 压缩完成后是这个样子: 解压完成后是这个样子: 大家在学python的时候肯定会遇到很多难题,以及对于新技术的追求,这里推荐一下我们的Python学习扣qun:784758214,这里是python学习者聚集地!!同时,自己是一名高级python开发工程师,从基础的python脚本到web开发.爬虫.django.数据挖掘等,零基础到项目实战的资料都有整理.送给每一位python的小

bzip2 一种块排序文件压缩软件

总览 bzip2 [ -cdfkqstvzVL123456789 ] [ filenames ... ] bunzip2 [ -fkvsVL ] [ filenames ... ] bzcat [ -s ] [ filenames ... ] bzip2recover filename 描述 bzip2 采用 Burrows-Wheeler 块排序文本压缩算法和 Huffman 编码方式压缩文件.压缩率一般比基于 LZ77/LZ78 的压缩软件好得多,其性能接近 PPM 族统计类压缩软件. 命令

关于压缩软件gzip和xz的简单对比

晚上由于处理磁盘报警的需要,进行了日志压缩,在此次压缩中分别使用了gzip和xz软件对文本进行了压缩,压缩的结果非常令人诧异. 出于对xz好奇的原因是因为在下载内核源代码时经常可以看到.xz格式的文件包,而且其大小比.gz和.bz2格式的文件都小一些.首先简单介绍一下gzip和xz: gzip:GZIP最早由Jean-loup Gailly和Mark Adler创建,用于UNⅨ系统的文件压缩.我们在Linux中经常会用到后缀为.gz的文件,它们就是GZIP格式的.现今已经成为Internet 上