月度归档:2013年08月

7z文件格式及其源码的分析(三)

上一篇在这里.  这是7z文件格式分析的第三篇, 相信有了前两篇的准备,你已经了解了7z源码的大致结构, 以及如何简单调试7z的源码了. 很多同学是不是迫不及待想要拔去7z的神秘外衣,看看究竟了. 好, 这就带你们一探乾坤. 本文开始,我们详细介绍7z的文件存储结构.

要了解7z的结构,  当然最好从官方的说明开始, 尽管这个说明非常简略, 但它的确是我入门时的救命稻草.

打开源码的 "DOC" 目录.  这里面就是官方所有的文档了. 其中只有二个文档跟结构相关:

1. 7zFormat.txt,   这是我们的主角, 里面介绍了7z文件的大体结构.

2. Methods.txt,  这里面介绍了7z压缩算法id的编码规则, 以后会用到.

 

我们从7zFormat.txt文件开始.

Archive structure
~~~~~~~~~~~~~~~~~ 
SignatureHeader
[PackedStreams]
[PackedStreamsForHeaders]
[
 Header 
 or 
 {
 Packed Header
 HeaderInfo
 }
]

 

上面就是7z文件的总体结构了.  我来稍微解释一下.  上面的代码中, 从波浪线往后开始算.    7z的文件结构基本上分为三部分:

1. 前文件头(就是最前面的header).

2. 压缩数据.

3. 尾文件头(就是放在文件末尾的header).

 

一, 前文件头就是上图中的 "SignatureHeader".  它是32个字节定长的.    前文件头其实记录的信息很少, 它的主要目的是记录尾文件头的位置, 压缩的主要结构都是存在尾文件头中.

它的结构如下:

SignatureHeader
~~~~~~~~~~~~~~~
 BYTE kSignature[6] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};
ArchiveVersion
 {
 BYTE Major; // now = 0
 BYTE Minor; // now = 2
 };
UINT32 StartHeaderCRC;
StartHeader
 {
 REAL_UINT64 NextHeaderOffset
 REAL_UINT64 NextHeaderSize
 UINT32 NextHeaderCRC
 }

 

先是固定的6个字节的值, 前两个字节的值是字母 '7' 和'z' 的ascii值.  后面四个字节是固定的: 0xbc, 0xaf, 0x27, 0x1c

然后是两个字节的版本号, 注意主版本号在前面, 次版本号在后面. 目前的版本号是: 0.2,  注意这是7z文件格式的版本号, 不是7z软件的版本号.

然后是四个字节的 UINT32 的值, (注意, 7z的所有数据都是采用小端在前的存储, 所以要注意这四个字节的实际存储顺序是低位字节在前面, 高位字节在后.  后面的所有数据都是这种结构, 所以以后就不再强调了.  ) .  这4个字节的值是做什么的呢?  先抛开这四个字节本身,   前文件头的32个字节中, 已经用去了 6 + 2 +4 =12 个, 还剩下20个字节.  对了, 这四个字节就是剩下的20个字节的CRC校验值.  具体的CRC算法源码, 在源码中的 "C" 文件夹下的 '7zCrc.c' 和 '7zCrc.h'.

最后这20个字节要一起介绍了.   先是8个字节的UINT64的值, 它记录的是尾文件头(上图中的NextHeader)与前文件头的距离, 这个距离是不算前面这32个字节头的, 也就是抛开前面32个字节开始计数的(解压器通过读取这个值,然后从第33个字节开始直接跳过这个距离, 就可以找到尾文件头了).  然后是8个字节的值, 记录了尾文件头的大小(解压的时候, 通过这个值就能读出尾文件头的长度了).  最后还有4个字节的值, 它也是一个Crc校验值,  是整个尾文件头的校验值.

这里需要注意的是, 上图中用的是 "REAL_UINT64" 这个表达方式, 它的意思就是我们通常理解的占8个字节的UInT64的值(当然是小端存储的啦).  这里用了"real", 真.  那是不是还有"假"的InT64呢. 答案是肯定的.   7z为了兼容压缩大文件(大于4G),这个问题曾一度是zip文件的噩梦,  早期的zip只能压缩小于4G的文件, 并且压缩后的总文件大小也不能超过4G, 后来专门做了标准升级. 好了扯远了.   7z一早设计就考虑到了大文件的问题, 所以很多地方都必须用int64来表达,  这样也会带来一个问题, 就是绝大多数case下, 都不可能超过4G(试问一下,你平时有多少压缩文件超过4G 呢),  所以呢, 就会造成8个字节的int64根本用不上, 多余的字节浪费了. 尤其在小文件压缩的时候,  很影响压缩比.  所以呢, 7z采取了一种巧妙的方法. 就是int64并不是都用8个字节存储, 它用一种简单的编码方式,进行变长存储. 在这个文件中也有描述:

REAL_UINT64 means real UINT64.
UINT64 means real UINT64 encoded with the following scheme:
Size of encoding sequence depends from first byte:
 First_Byte Extra_Bytes Value
 (binary) 
 0xxxxxxx : ( xxxxxxx )
 10xxxxxx BYTE y[1] : ( xxxxxx << (8 * 1)) + y
 110xxxxx BYTE y[2] : ( xxxxx << (8 * 2)) + y
 ...
 1111110x BYTE y[6] : ( x << (8 * 6)) + y
 11111110 BYTE y[7] : y
 11111111 BYTE y[8] : y

 

上面就是编码方式: 就是根据第一个字节的内容来判断后面还有多少个字节.

如果第一个字节的最高位是 0, 那后面就没有字节了. 范围在 0-127.

如果第一个字节的最高两位是 1, 0, 表示它后面还有一个字节.  读取方式是: ( xxxxxx << (8 * 1)) + y

依次类推, 不再详细介绍了.

它的写入方法在: \CPP\7zip\Archive\7z\7zOut.cpp 文件的 第204行:

void COutArchive::WriteNumber(UInt64 value)
{
  Byte firstByte = 0;
  Byte mask = 0x80;
  int i;
  for (i = 0; i < 8; i++)
  {
    if (value < ((UInt64(1) << ( 7  * (i + 1)))))
    {
      firstByte |= Byte(value >> (8 * i));
      break;
    }
    firstByte |= mask;
    mask >>= 1;
  }
  WriteByte(firstByte);
  for (;i > 0; i--)
  {
    WriteByte((Byte)value);
    value >>= 8;
  }
}

 

它的读取方法在: 7zIn.cpp 的第210行:

UInt64 CInByte2::ReadNumber()
{
  if (_pos >= _size)
    ThrowEndOfData();
  Byte firstByte = _buffer[_pos++];
  Byte mask = 0x80;
  UInt64 value = 0;
  for (int i = 0; i < 8; i++)
  {
    if ((firstByte & mask) == 0)
    {
      UInt64 highPart = firstByte & (mask - 1);
      value += (highPart << (i * 8));
      return value;
    }
    if (_pos >= _size)
      ThrowEndOfData();
    value |= ((UInt64)_buffer[_pos++] << (8 * i));
    mask >>= 1;
  }
  return value;
}

 

这里贴出来给大家参考一下.   其实, 后面提到的Uint64如果没有特别说明是8个字节, 那它都是采用这种压缩方式存储的. 但是注意UInt32 无论何时都是占4个字节的, 没有采用压缩.

 

二, 第二部分比较简单, 它会比较大, 简单的说, 它就是文件压缩后的压缩数据存放地点. 结构如下:

[PackedStreams]
[PackedStreamsForHeaders]

简单的说, 7z会把文件压缩成若干个"Pack", 就是包的意思, 这里就是按顺序存储这些pack的. 每个pack的位置和大小信息都会记录在尾header中, 解压的时候就会从这里读出pack,然后解压出来.   这里都是简单的排布压缩后的数据, 所以没有多少细节需要介绍的.

 

三, 真正复杂的主角出场了, 尾文件头,  就是7z中所谓的 nextHeader.

Header structure
~~~~~~~~~~~~~~~~
{
ArchiveProperties
AdditionalStreams
{
PackInfo
{
PackPos
NumPackStreams
Sizes[NumPackStreams]
CRCs[NumPackStreams]
}
CodersInfo
{
NumFolders
Folders[NumFolders]
{
NumCoders
CodersInfo[NumCoders]
{
ID
NumInStreams;
NumOutStreams;
PropertiesSize
Properties[PropertiesSize]
}
NumBindPairs
BindPairsInfo[NumBindPairs]
{
InIndex;
OutIndex;
}
PackedIndices
}
UnPackSize[Folders][Folders.NumOutstreams]
CRCs[NumFolders]
}
SubStreamsInfo
{
NumUnPackStreamsInFolders[NumFolders];
UnPackSizes[]
CRCs[]
}
}
MainStreamsInfo
{
(Same as in AdditionalStreams)
}
FilesInfo
{
NumFiles
Properties[]
{
ID
Size
Data
}
}
}

尾header的结构非常复杂,  里面有很多压缩概念,   如若没有理解压缩过程, 单独的纯字节层面介绍是没有意义的.

我们下一篇开始介绍详细的7z压缩流程,  介绍7z是如何把一系列的文件, 压缩成一个大文件的,  怎样利用压缩算放, 怎样排布文件结构.  同时我们再一边来介绍这个尾header的结构.

希望大家多多支持,  给我动力写下去.

欢迎大家访问我的个人独立博客: http://byNeil.com

 

记得顶啊, 小伙伴们.

 

 

 

 

 

 

 

 
byNeil
byNeil.com

原文来自 Blog by Neil, post 7z文件格式及其源码的分析(三) 转载请注明出处。本站保留一切权力

7z文件格式及其源码的分析(二)

这是第二篇, 第一篇在这里: 这一篇开始分析7z的源码结构.

一. 准备工作:

1. 源码下载:

可以从官方中文主页下载:http://sparanoid.com/lab/7z/.  为了方便, 这里直接给出下载链接: http://downloads.sourceforge.net/sevenzip/7z920.tar.bz2 .

2. 工具准备:

源码中给的工程文件都是vc6.0的工程.  作者说他不喜欢新vs的界面. 哎.  不过没关系, 我们使用VS2008也一样可以. 有极少地方需要修改一下.  我们使用VS2008 sp1 作为开发环境.

 

二. HelloWorld:

我们在根目录下新建一个目录"7z", 把源码都解压到这个位置.

我们稍后再详细解释这些目录的意思.   先来一个helloworld, 程序员的最爱.

请直接打开这个路径: 7z\CPP\7zip\Bundles\Alone\

用vs打开其中的 Alone.dsw 文件.   提示要转换工程文件. 点击同意.   然后编译这个工程. 如果不出意外的话, 应该提示你编译成功了.

这个时候, 打开 c:\util\  目录.  里面已经生成7za.exe.    注意, 这里是C盘的绝对路径 :  c:\UTIL\7za.exe

好了, 这个7za.exe  就是一个包含全部7z功能的压缩,解压命令行工具了.

我们可以从命令行进入该目录. 输入 7za.exe 回车. 就能看到它的帮助信息啦.

 

我们先拷贝一个文件到这个目录, 比如拷贝一个test.txt 到c:\util\ 里面去.  我们用命令行来压缩它.

==============

c:\util>7za.exe  a  test.7z  test.txt

==============

这个命令把test.txt  压缩成test.7z.   这两个文件名都是可以带路径的,  为了方便, 我们都拷贝到当前目录了.

恩, 我们再来试试解压.

==============

c:\util>7za.exe x  test.7z  -oout

==============

这个命令可以吧test.7z 解压到当前的out目录下.

试试这两个命令吧, 是不是还不错.

 

三, 目录结构详解:

我们先回到最外层目录:

7z源码基本上是按文件类型分类的.

1.  上面的ASM目录, 其中保存汇编代码.  为了极限的性能, 7z使用了部分汇编代码, crc计算, 和aes加密.  这两点都不是必须的, 实际上, 它们都有c语言的实现. 7z会检测, 如果cpu提供了硬件的aes指令, 就会使用硬件aes汇编指令, 而不会使用自己的aes函数.

2. "C" 目录是7z的核心.   实际上, 7z所有的核心算法都是用c语言实现的. 包括所有的压缩算法, 以及我们的主角7z打包算法.   这些c代码非常强悍, 部分代码可以跨平台编译, 甚至能在嵌入式平台上编译.

(a)  这里面有几个工程文件值得我们注意, 找到这个位置: 7z\C\Util\7z

我们来编译它. 它会在debug目录下生成  7zdec.exe

这是一个最小化的指包含7z解压器的独立exe程序.  有了它就可以解压文件了.

 

(b) 找到这个目录,  7z\C\Util\Lzma

编译之后也会在绝对目录生成.   c:\util\7lzma.exe.  这是一个lzma压缩算法的工具.  只能压缩或解压单个文件. 只包含lzma算法.

这可以用来测试lzma算法.

 

(c) 打开这个目录 7z\C\Util\LzmaLib.

这个工程用来生成 只包含lzma算法的 dll.  以便你的程序调用lzma算法.

 

3. "CPP" 目录是也是7z的重点.

前面说了核心的算法都在C目录下面.  那么CPP目录是做什么的呢.   除了核心的算法之外, 7z还有非常丰富的外围功能.  就是他的文件管理器, 以及右键菜单支持等等. 这些与UI和系统相关的功能都是用c++实现的.     此外, C中的核心算法在cpp目录中都有c++的面向对象的封装.  我们来逐一介绍它的子目录:

a ) "Windows" 目录.

其中包含了与windows集成的功能. 包括菜单集成, 剪贴板支持, 文件io,等等.

 

b) "Common" 目录.

通用的工具类.

 

c ) 我们重点介绍 7zip 目录:

 

(1) "Archive" 目录. 包含各种 archive ("打包") 算法的代码.   因为7z不光支持7z文件,  还支持zip, rar, chm等等其他的打包文件格式.

这里面每个目录就是一种格式.   7z目录当然就是我们的主角7z格式了. ( 这里面的代码是对C文件夹里面的代码的c++封装. )  这里面有一个工程文件.

打开这个工程文件, 然后在工程上面点右键,查看属性:

可以看到, 它的输出路径是: C:\Program Files\7-zip\Formats\7z.dll

这是什么意思呢?   对,  这个工程就是封装7z格式的dll.  这个工程的目的就是给我们演示如何让7z支持我们的自定义格式.   具体怎么实现自定义格式, 可以参考这个工程以及 它周围的其他文件夹格式, 比如:Cab, Chm, 等等. 实现相应的com接口, 然后编译到这个目录下, 7z就能自动调用了.  以后有时间我们再详细介绍这个.

 

(2) 再来看 "Bundles" 目录.

这里面的Alone目录, 我们在前面 写 helloworld 的时候已经见识过了. 它是一个包含全部7z功能的console 的exe.

其中我们再介绍另一个重要的目录,  就是Format7zF.

打开它, 编译,  会提示几个链接错误.  原因是因为作者使用的是vc6. 和我们使用的vs2008一些编译选项不支持了.

分别在这几个汇编文件上点击右键:

找到"CommandLine" 参数, 把其中的参数删除:  -omf -WX -W3,  只保留 -c

 

然后再编译就会成功了.

编译完成之后, 它会在绝对目录下生成一个dll.  C:\Program Files\7-Zip\7z.dll

这个dll是做什么的呢?

它是包含7z全部功能的dll.   第三方的程序可以调用这个dll实现7z的所有功能.   包括7z自己本身的文件管理器 都是通过这种方式调用的.

 

好了, 基本上 7z源码的主要目录都介绍完了.  大家有什么疑问可以留言交流.

我们之后的讲解都将使用: 7z\CPP\7zip\Bundles\Alone 这个目录下的工程配合命令行参数来调试讲解. 因为这是一个包含7z全部功能的console程序, 简单好调试.

 

如果你不想了解7z的文件结构,  只是想在你的程序中集成进处理7z文件的功能. 那么已经足够了.  可以打开上面介绍的相应工程,  把源码集成到你的工程中, 或者直接调用: 7z\CPP\7zip\Bundles\Format7zF 生成的dll. 都是不错的选择.

 

下一节开始, 我们将开始讲解7z的文件格式结构了.  完成以后, 我会把地址更新到这里.

欢迎大家访问我的独立博客交流讨论. http://byNeil.com
byNeil
byNeil.com

原文来自 Blog by Neil, post 7z文件格式及其源码的分析(二) 转载请注明出处。本站保留一切权力

等等,你可能误解nodejs了–通俗的概括nodejs的真相

最近刚把产品从cpp平台迁移到nodejs平台了.  很多以前关于nodejs的观念被颠覆了. 这里分享出来, 欢迎大家批评指正.

"nodejs是做服务器端开发的, 它一定和web相关,几乎是用来做网站开发的."  这是我之前一直的观念.  相信这可能也是很多人对nodejs的初步认识吧.  但后来我才发现, 我可能错了.

第一个问题:  nodejs到底是什么?

http://nodejs.org/ 官方主页上有一段解释: "Node.js is a platform built on Chrome's JavaScript runtime for easily building fast, scalable network applications. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient, perfect for data-intensive real-time applications that run across distributed devices."

我们注意其中的几个关键字:  nodejs是一个平台,  它构建在chrome的v8引擎之上,  能简易的构建快速,可扩展的网络应用程序.......

这里官方用的"网络应用程序",  整个描述没有提到"web", "server" 等等概念.  这段话的描述中, 有两个是重点, 第一,就是chrome的v8引擎.  第二, 是事件驱动的非阻塞io模型.   把握住这两点,  我觉得就算掌握了nodejs的真谛了.

这么说吧,  举个例子, 类比来说,  概念上, nodejs相当于.net,   jvm 或者 python.   它是一个运行平台, 只不过它运行的是javascript语言而已.   类似地,  .net一般运行C#, vb等编译过后的il.  而jvm一般运行java编译成的字节码,  python一般运行python语言.

你可能要问, 那么nodejs是不是也能实现 .net等等这些平台的功能呢.  比如写个窗口桌面程序, 做socket网络通信, 以及访问磁盘文件等等.

恩, 这些问题的答案都是肯定的.

nodejs核心主要是由两部分组成的:

第一, 是v8引擎, 它负责把javascript代码解释成本地的二进制代码运行.

第二, 是libuv,  类似windows上的窗口消息机制, 它主要负责订阅和处理系统的各种内核消息. 而且它也实现了消息循环(是不是很耳熟? 没错, 这个几乎就和windows 的窗口消息循环是一个概念.).  它的前身是linux上的libev, 专门封装linux上的内核消息机制.  后来nodejs重写了它, 并在windows上使用iocp技术重新实现了一遍.  所以nodejs现在能跨平台运行在windows上了.

 

nodejs其实就是libuv的一个应用而已.

你自己写程序也可以集成libuv进来, 这样你的c++程序就有了消息循环了. 不再是简单main函数了. 你可以订阅系统的事件, 然后当事件发生时, 系统会调用你的回调函数, 就跟windows上的button click事件一样方便. 而且是跨平台的哦. 是不是很酷.    你几乎可以订阅所有的系统事件,  比如socket事件, 文件读写事件等等.

nodejs简单的说只是把javascript解释成c++的回调, 并挂在libuv消息循环上, 等待处理.  这样就实现了非阻塞的异步处理机制.

那么为什么是javascript而不是其他的语言.  很简单, 因为javascript的闭包.  这非常适合做回调函数.  因为我们一般都希望当回调发生时, 它能记住它原来所在的上下文.  这就是闭包最好的应用场景.

这里有libuv的详细介绍 http://nikhilm.github.io/uvbook/.

好像扯远了,  说nodejs的, 怎么扯到libuv了.  很简单, 因为 nodejs只是libuv的一个应用.  先了解libuv才能了解nodejs的实质和前世今生.

我们再回来说nodejs.

从另一个角度看,   上面的工作都分别由v8和libuv做了.  那么nodejs到底做了什么呢?   我们先看一下nodejs的文档: http://nodejs.org/api/

对了,除了用javascript封装libuv框架之外,   nodejs就是实现了这些api 功能.  这些api大部分是用javascript写的, 也有一部分是c++写的.

这是nodejs官方的仓库, https://github.com/joyent  其中有很多nodejs的插件. 有了这些nodejs就可以实现非常丰富的功能了.

作为结尾, 写一个简单的nodejs 常规helloworld 程序.

//test.js

//=================

console.log("hello world!")

//=================

存成test.js.  然后运行: node test.js

就能看到效果了.

怎么样,  看起来是不是很像python的感觉.  但是用的是javascript哦.  用这个代替python, 是不是爽死了.

就到这吧.  关于libuv, 关于nodejs插件.  等等话题, 希望能跟大家沟通交流.

欢迎大家访问我的独立博客: http://byNeil.com

 
byNeil
byNeil.com

原文来自 Blog by Neil, post 等等,你可能误解nodejs了–通俗的概括nodejs的真相 转载请注明出处。本站保留一切权力

7z文件格式及其源码的分析

本文是一个系列. 主要是分享我最近一年做7z文件开发的经验. 主要包括7z官方源码的结构分析, 以及7z文件格式的分析. 其中涉及到7z源码结构的各个细节, 以及7z文件格式的具体细节. 本文适合对象: 想要了解学习7z源码的开发人员, 想要了解7z文件格式细节, 做7z文件压缩器和解压器的开发人员, 以及其他压缩文件爱好者等等.

目前7z的最新稳定版是9.20, 而9.30版本还在alpha版本. 所以本文是基于其9.20版本.  我将尽可能详细的描述所有细节, 但到目前为止我了解到的细节大概能到八成到九成的样子. 也不是百分百.  希望能和大家共同讨论学习.  这些信息足以开发一个工业级别的高兼容性的7z压缩器和解压器了.

本文首发在我的个人独立博客  http://byNeil.com 以及博客园.  欢迎大家浏览我的独立博客, 留言交流. 转载请注明出处链接. 本人保留一切权利.  但本人不对使用本文提供的代码造成的损失负责.

好了, 憋死我了, 前面的客套话终于说完了.  有人可能要问, 为什么要分析7z文件格式? 这个不是开放的吗? 为什么我前面说我只了解到八,九成, 而不是百分百呢?

我先来解释这几个问题, 这能说明本文的必要性, 以及看下去的必要性.  首先7z的确是开放的. 但他的格式说明非常简单, 简直是简陋. 简单的一个txt文件,寥寥几十行算不上说明的符号, 对复杂的7z格式来说, 简直就是天书.( 后面分析7z源码的时候会详细说道这一点. )  所以如果你接到老板的一个通知:"我们要做7z兼容的压缩解压器" 的时候, 你就要崩溃了.  因为相对于zip这些经过标准化的文件格式来说, 7z几乎就是一个黑洞.(zip有标准化的 spec, 里面有详细到字节级别的说明).   所以我分析7z格式可以说有一半是通过阅读源码逆向推测出文件格式的, 再经过反复和源码对比测试证明其正确性的.  所以我只能说了解到了八九成, 而不是百分百.

先分享一些有用的链接:

7z的官方主页: http://www.7-zip.org/  (它托管在sourceforge的虚拟机上, 本来能打开的, 但是前一段时间开始被墙了, 我实在想不到墙它的理由, 可能是被sourceforge主机上其他的网站拖累的吧,你懂的).

这是sourceforge上7z的论坛: http://sourceforge.net/p/sevenzip/discussion/45797  . 论坛比较活跃, 每天都有新帖. 而且7z作者也在上面每天亲自回帖.  由于作者是俄罗斯人, 所以时区跟我们差的不多.  一般留言4个小时左右,  作者就能回复吧. 我问过几个问题, 都是这样的. 当然也有些帖子作者懒得回, 那就另当别论了. 呵呵.

7z的官方中文镜像: http://sparanoid.com/lab/7z/    这个不需要翻墙.  是官方给出的中文版链接. 值得信赖. 上面的内容基本和官方主页保持一致.

 

我们先从几个概念开始吧 :    7z软件 和7z文件.   7z文件指的是一种后缀名为.7z的文件.    7z软件指的是作者开发的生成和操作7z文件的工具.  但是现在7z软件已经发展到不光支持7z格式的文件了, 还能额外的生成和编辑另外几十种文件格式了. 其中包括我们熟知的zip格式, rar格式, iso格式等等,  也包括一些不可思议的格式, 比如: CAB, CHM, CPIO, CramFS, DEB, DMG, FAT . 看眼花了吧.  好吧, 本文主要讨论 7z文件格式, 以及7z软件中主要和7z文件相关的功能. 当然也会粗略的涉及到其他的一些有用的功能,  比如如何给7z软件写插件, 让他支持我们自己定义的文件格式.

 

再来几个概念.  说到压缩文件, 一般会遇到两个概念,   一个是 "Compress"(压缩) 和"Archive" (存档).    "存档" 这个词个人觉得不好理解. 我个人把 "Archive" 叫做 "打包".

举个例子,  比如有一堆毛巾,  每一条毛巾代表一个文件.    "Compress"(压缩)的意思就是把毛巾里面的水拧干, 达到压缩的目的.  而"Archive"(打包) 的意思就是把这些毛巾包成一个大包, 便于运输.     所以你可能想到了, 要运输一堆这样的毛巾可能有两种方法: 第一种: 先把每条毛巾拧干并折成方块(压缩), 再把这些方块组合成一个大包(打包).  第二种, 先把这些毛巾包成一个大包(打包),  然后再把这个大包拧干.    凭经验你可能已经意识到, 前一种方法比较好处理, 而且压缩比比较大.  后一种方法就弱一点了.

对了, 前一种就是先压缩后打包的方式. 7z, zip 和rar等就是用的这种方法.   后一种就是先打包, 后压缩的方法. 常见的tar.gz的文件就是用这种方法的. 先用tar打包, 在用gz压缩.

 

对于7z 我们再具体解释一下 "压缩" 和 "打包" 的概念.

 

7z 文件格式严格的说是一种"打包"的格式,  它规定了打包的方法.   而"压缩"的任务是由不同的算法完成的.    "压缩算法"负责把毛巾里的水拧干. 具体来讲就是把一个文件按照一定规则变小.  压缩算法一般只能处理单个文件, 对于多个文件, 只能单个文件压缩, 然后再打包.

(当然,前面也说到了, 第二种方法就是先把文件打包, 然后再压缩. tar.gz就是这样的. tar工具就是简单的把所有的文件首尾相接, 变成一个大文件, 然后再用压缩算法一次压缩的.  这个不是本文的讨论对象, 所以以后就不提了.)

 

7z默认使用的是lzma压缩算法.   单个文件会先用lzma压缩算法压缩,  然后7z负责把压缩过后的文件打包.   (这个跟zip类似, zip文件也是打包格式, 它默认使用deflate算法压缩.)  7z还支持封装其他几种压缩算法, 比如: Lzma2, ppmd, bzip2和deflate.

这些压缩算法在7z里面都有源码,  也不是本文要讨论的重点.  我们将重点讨论7z的打包格式. 就是介绍7z具体是怎样把压缩过后的文件封装打包的.  期间也会夹杂介绍其中一些算法.  后面如果有时间, 我会再单独介绍这些算法的具体实现.

终于把前期准备介绍完了,   有点繁琐.

下一篇我们将开始具体分析介绍7z的源码.    完成之后, 我会把第二篇的链接更新到这里. 当然你也可以在我的博客中搜索到.

大家多多支持哦.

 

 

 

 

 

 

 

 

 

 

 
byNeil
byNeil.com

原文来自 Blog by Neil, post 7z文件格式及其源码的分析 转载请注明出处。本站保留一切权力