Home > 程序/算法 > zpack:一个简单的文件打包格式

zpack:一个简单的文件打包格式

January 18th, 2011 Leave a comment Go to comments

最近实现了一个简单的文件打包格式

一向很喜欢简单高效的东西,所以非必要的加密,压缩功能一概欠奉。反正也开源了,用户很容易自行添加。

文件以文件名的hash作为检索,为了防止hash冲突的情况,除了用来建立hash table的主hash以外,索引表里还另外保存了两个用不同算法算出来的hash值。这样一来,读取包内文件时并不需要原始的文件名信息,只要根据输入的文件名算出来的3个hash值都和hash table里保存的相应值一致,就基本可以认定是用户所需要的。当然,对于32bit的hash来说冲突的情况实际上很少,而计算hash也有一定开销(虽然和磁盘io相比基本可以忽略),如果包内文件又很少,可以只比较两个,甚至一个hash值。

包内文件采用简单的首尾相连的形式连续存放,索引表放在文件最后,这样在包内文件变化时能最小化写操作。删除文件时,并不把后面的数据前移,而是简单的留下空洞;添加文件时会优先利用之前留下的空洞。这样在多次添加/删除操作后可能会在包内留下一些无法再利用的小碎片,当用户觉得有必要进行整理时(例如碎片空间达到总大小的一定比例),可以调用zpak提供的defrag函数来整理。

虽然包文件看似具有目录结构(见上图),但实际上包内文件并没有以树状形式存储,目录信息只存在于文件名中。为方便起见,在zpack核心代码之外,提供了ZpExplorer类让用户可以以目录形式进行操作,比如删除目录,添加目录,解压目录等。

最终基本上达到了设计目的,无论从功能,接口,代码量上看都不大容易再简化了。原来计划只提供一个命令行工具的,后来也不能免俗,做了一个图中所示类似Windows Explorer的东西。

后记:

很多人向我提出以下几个问题(建议),这里统一解答一下

  • 希望提供一个patch更新机制,方便用在网络游戏中

毫无疑问,网络游戏更新补丁时经常会需要添加或修改资源包里的文件,但这并不意味着patch机制应该成为打包格式的一部分。所谓更新,无非就是添加文件(目录),删除文件(目录),用新的文件代替旧的文件,这些zpack都已经提供了接口,还需要更多的功能吗?

另外有用户提出希望添加包文件合并的功能,也是为了补丁方便。我提出的替代方案是把一个包(比较小的那个)先释放到硬盘上,然后把所有文件/目录添加到另一个包里。虽然直接将包合并或许能快一些(因为可以节省一步中转),但我认为节省的这点时间和下载补丁的时间相比简直是九牛一毛。况且zpack还没有提供压缩功能,补丁包压成zip下载似乎更合算

  • 是否线程安全

不是。一个IPackage(以及打开的IFile)不能在多个线程同时使用,即使是只读的也不行。因为STL的fstream不是线程安全的。

如果需要多线程同时读取包内文件,可以每个线程分别调用zp::open,打开一份独占的IPackage实例,这样就不会互相影响了

  • 用开源的打包格式,岂不是资源包里的东西都随便让人看了

没错。暴雪的mpq你都随便看了,你的游戏有什么需要藏着掖着的?

退一步说,如果希望不要太容易被用户看到包里的东西,可以自己改一下包格式。开源嘛,代码全都在你手里了。

我比较偏向的方案是,如果有需要保密的文件,比如比较敏感的脚本,数据表什么的,可以在打到包里之前就做好加密。

Categories: 程序/算法 Tags:
  1. January 31st, 2011 at 11:09 | #1

    谢谢博主分享

  2. Glcolor
    February 6th, 2011 at 12:30 | #2

    just want to say:
    Nice Work!

  3. Viking
    August 26th, 2011 at 11:16 | #3

    学习一下。博主是个专注的人!谢谢!

  4. WilliamZ
    October 10th, 2012 at 12:53 | #4

    非常欣赏博主这样的开源精神,非常感谢!

  5. Citizen2047
    February 24th, 2014 at 17:46 | #5

    有sample吗?求sample – –

 

Spam Protection by WP-SpamFree