编辑大型二进制文件

时间:2011-10-27 17:14:58

标签: c# c++ file

我正忙着一个小项目,它有很多数据,比如图像文本文件和其他东西,我试图将它们全部打包在一个大文件或多个大文件中,所以程序文件夹看起来不像凌乱。

但问题是如何编辑这些文件。我已经考虑过文件结构了,它会是这样的:

[DWORD] Number of files

     [DWORD]FileId
     [STRING]FileName
     [DWORD]FileSize
     [DWORD]FileIndex

[BYTES]All the files

所以第一部分太快得到所有文件的列表,而FileIndex是二进制文件中的Position,所以我也可以设置指针,例如300并读取文件。

但是如果我想创建一个补丁并对其进行编辑,我将不得不在我编辑的文件之后读取所有字节并将它们全部复制回来,这可能需要几年的文件才能使用。

插入所有文件后,二进制文件可能只有几百MB。

那么其他程序如何做到这一点,例如游戏使用这些大文件,还有很多补丁是否有某种技巧可以更快地插入额外的字节?

7 个答案:

答案 0 :(得分:3)

在文件中间插入字节没有“技巧”。

通常解决方案涉及将文件添加到文件末尾,然后在索引中切换它们的位置。然后你遇到了必须对文件进行碎片整理的问题。您可以将文件分成大块,这可以减轻一些碎片整理问题,但文件不是连续的。

如果您正在处理非静态数据,除非您绝对必须,否则我不建议这样做。我见过绝对优秀的软件工程师花了相当多的时间来写一个合理的实现。

使用sqlite作为虚拟文件系统可能是一个可行的解决方案。但话说回来,将数据文件放在另一个文件夹中也是如此,因此看起来并不“混乱”。

答案 1 :(得分:3)

如果可能的话,我可能会将数据打包成一个zip文件。这不仅会清理你的目录,而且(特别是你提到的文本文件)基本上免费提供一些压缩。当然,还有很多用于创建,检查,修改等文件的现有工具和库。

使用zlib(例如),大部分工作都是为您处理的(例如minizip中所示)。

答案 2 :(得分:1)

您可以将打包和编辑程序视为自定义内存分配器:

  1. 使用最小块大小 - 添加文件时,请使用足够的整体 用于适合文件的块。这会自动为文件提供一些空间 在不影响其他人的情况下成长。
  2. 当文件对于当前分配而言太大时,将其移动到包的末尾。
  3. 将空闲块标记为空闲,并将偏移量保持为 包头中的空闲列表。添加其他文件时,首先 检查是否有足够大的空闲区块。
  4. 将文件扩展到当前块之后,请检查以下块是否在空闲列表中。
  5. 如果免费列表太长(碎片太多),请联系该软件包。向前移动每个文件以在第一个空闲块中开始。这将不得不重写整个文件,但很少发生。
  6. 或者,使用类似FAT的内容,而不是简单的目录。对于每个文件,存储块和大小的列表。当您将文件扩展到其当前分配之外时,添加另一个具有余数的块。根据需要偶尔进行碎片整理。

    这两个都会给包增加一点开销,但留下空白实际上是在每个插页上重写整个内容的唯一选择。

答案 3 :(得分:1)

诀窍是通过覆盖数据来制作补丁。否则,有可用于管理大量数据的系统,例如数据库。

您可以创建一个伴随程序的数据库文件,并将所有数据保存在那里,而不是文件中。您甚至可以使用SQLite将数据库代码嵌入到应用程序中,或者使用外部数据库,如Sql Server,Oracle SQL或MySql。

您所描述的基本上是实现您自己的文件系统。要使其有效,这是一项棘手且非常困难的任务。

答案 4 :(得分:0)

插入字节不能用于您描述的文件以外的文件。这与编程语言无关。这就是文件系统的工作方式......

您可以覆盖部分文件,但只要您尊重字节数。

答案 5 :(得分:0)

您是否考虑过使用.zip文件?我一直在看那些存储多个文件的格式,而底层文件实际上是一个zip文件。关于这一点的好处是zip库为您处理低级位跟踪的东西。

想到几个例子:

  • Word .docx文件实际上是一个zip(将一个重命名为.zip,你可以打开它 - 它里面有整个文件夹)
  • Silverlight包使用的.xap文件是另一个。

答案 6 :(得分:0)

您可以使用内存映射文件支持的托管共享内存。您仍需要为整个文件提供足够的地址空间,但不需要将整个文件复制到内存中。您可以将大多数标准工具与共享内存分配器一起使用,但您可以快速发现在任何地方指定自定义分配器都是件苦差事。但好消息是你不需要自己实现它,你可以使用 Boost.Interprocess ,它已经具备了unix和windows的所有必要功能。