【问题标题】:How to delete parts from a binary file in C++如何从 C++ 中的二进制文件中删除部分
【发布时间】:2011-09-20 19:40:17
【问题描述】:

我想使用 C++ 从二进制文件中删除部分。二进制文件大约 5-10 MB。

我想做的事:

  1. 搜索 ANSI 字符串“某物”
  2. 一旦我找到这个字符串,我想删除下面的 n 个字节,例如下面的 1 MB 数据。我想删除那些字符,而不是用 NULL 填充它们,从而使文件更小。
  3. 我想将修改后的文件保存到一个新的二进制文件中,和原来的文件一样,除了我删除的少了n个字节。

你能给我一些建议/最佳实践如何最有效地做到这一点吗?我应该先将文件加载到内存中吗?

如何有效地搜索 ANSI 字符串?我的意思是,在找到该字符串之前,我可能必须跳过几兆字节的数据。 >> 有人告诉我我应该在另一个问题中问它,所以它在这里: How to look for an ANSI string in a binary file?

如何删除 n 个字节并将其高效地写入新文件?

好的,我不需要它超级高效,文件不会大于 10 MB,运行几秒钟就可以了。

【问题讨论】:

  • 您想要可移植的代码吗?或者您会对特定于平台的解决方案感到满意吗?
  • 我希望它是一个命令行应用程序,可以在 Linux 和 VS2010 下编译。在 Linux 和 VS2010 下编译会不会更难?
  • 如果你能忍受编写 3 行依赖于操作系统的代码,我建议使用内存映射。这种事情真是太棒了,你不能更有效地做到这一点。删除范围等于 memcpy 并根据删除范围的长度截断文件。另外,它超级快。
  • 或者只是将文件分两块写在要删除的段之前和之后。
  • 这确实应该作为几个问题来问。

标签: c++ search replace binaryfiles ifstream


【解决方案1】:

有许多快速字符串搜索例程比测试每个字符的性能要好得多。例如,当尝试查找“某物”时,只需测试每 9 个字符。

这是我为之前的问题写的一个例子:code review: finding </body> tag reverse search on a non-null terminated char str

【讨论】:

  • 但是将 5-10 MB 的文件复制成字符串并使用 string::find 效率如何?
  • @zsero:我猜这取决于你的string::find 实现。大多数效率不高。
  • @Loduwijk: std::string 被计算在内,不是 NUL 终止的。
  • 但是每个第 9 个字符都需要针对多个事物进行测试,对吧?这比针对一件事测试每个角色更好吗?
  • @Ben:你的意思是平均只需要测试每9个字符吗?因为如果不是,我认为你错了。
【解决方案2】:

对于 5-10MB 的文件,如果您的系统支持,我会查看 writev()。将整个文件读入内存,因为它足够小。扫描要删除的字节。将 writev() 传递给 iovecs 列表(这将只是指向您的读取缓冲区和长度的指针),然后您可以在单个系统调用中重写整个修改后的内容。

【讨论】:

    【解决方案3】:

    首先,如果我理解您在“我如何有效搜索”小节中的意思,那么如果目标字符串可能在前几兆字节中,您就不能在搜索中跳过几兆字节的数据。

    至于将文件加载到内存中,如果这样做,请不要忘记确保内存中有足够的空间用于整个文件。如果您使用实用程序并发现要使用的 2GB 文件无法放入您剩余的 1.5GB 内存,您会感到沮丧。

    我将假设您将加载到内存或内存映射它以供以下使用。

    您确实明确表示这是一个二进制文件,因此这意味着您不能使用普通的 C++ 字符串搜索/匹配,因为文件数据中的空字符会混淆它(在没有匹配的情况下过早结束它)。相反,您可以使用 memchr 查找目标中第一个字节的第一次出现,并使用 memcmp 将接下来的几个字节与目标中的字节进行比较;继续使用 memchr/memcmp 对来扫描整个事物,直到找到为止。这不是最有效的方法,因为有更好的模式匹配算法,但我想这是一种有效的方法。

    要“删除” n 个字节,您必须在这 n 个字节之后实际移动数据,将整个内容复制到新位置。

    如果您实际上将数据从磁盘复制到内存,那么在那里操作并写入新文件会更快。否则,一旦在磁盘上找到要开始删除的位置,就可以打开一个新文件进行写入,从第一个文件读取 X 个字节,其中 X 是第一个文件的文件指针位置,然后写入它们直接进入第二个文件,然后在第一个文件中查找 X+n 并从那里对 file1 的 eof 执行相同的操作,将其附加到您已经放入 file2 的内容中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-11-26
      • 1970-01-01
      • 2013-01-29
      • 2014-06-12
      • 1970-01-01
      • 2015-02-27
      • 2012-06-11
      • 2012-01-18
      相关资源
      最近更新 更多