【问题标题】:file operation in binary vs text mode -- performance concern二进制与文本模式下的文件操作——性能问题
【发布时间】:2012-08-16 05:57:45
【问题描述】:

在许多项目中,我看到数据对象/结构以二进制模式写入文件,然后再次以二进制模式从文件中取回。

我想知道他们为什么以二进制模式执行此操作?文本和二进制模式之间的性能差异?如果不是,那么什么时候使用二进制模式或文本模式?

【问题讨论】:

  • 我怀疑这是 stackoverflow.com/questions/229924/… 的副本,但我不确定。
  • @jogojapan,差不多。但是那个帖子并没有完全回答我的问题。
  • 读取/使用二进制文件必须知道它的结构

标签: c++ c file-io


【解决方案1】:

二进制更快。考虑一个存储在 32 位(4 个字节)中的整数,例如 123456。如果您将其写为二进制(这是它在计算机中的表示方式),它将占用 4 个字节(忽略项目之间的填充以在结构中对齐)。

要将数字写为文本,必须将其转换为字符串(转换需要一些开销和存储内存)然后写出来,因为要表示 6 个字符,所以至少需要 6 个字节数字。这不包括任何额外的填充,例如用于对齐的空格或用于读取/分隔数据的分隔符。

现在,如果您认为您有数千个项目,那么额外的时间可能会加起来并需要更多空间,这将需要更长的时间来读入,然后在您拥有额外的时间后转换回二进制文件进行存储将值读入内存。

文本的优势在于它更容易被人们阅读,而不是试图阅读二进制数据或数据的十六进制转储。

【讨论】:

  • 我发现你的回答更容易理解。 :-)
【解决方案2】:

如果您的程序是唯一要使用该文件的程序,您可以使用二进制文件“按原样”保存内部结构。

但是,如果您想与其他程序或通过 Internet 交换文件,那么二进制格式就不那么好了。例如,想想大端与小端机器的问题。此外,文件或数据的接收者很可能无法访问您的代码和结构,因此基于文本的格式可能更容易解析并实现到自己的结构中。

关于性能,确实直接读取和写入内部结构会更快,因为您不必将它们(也称为编组)转换为另一种格式。

【讨论】:

  • +1。正如您所指出的,我是唯一使用这些数据对象/结构的人,我想将它们保存到文件中并从文件中检索它们。在这种情况下,我认为文本文件不会有帮助,通过 文本文件,您的意思是我应该将每个数据对象/结构的值作为 纯文本 写入文件,然后将这些文本读回并使用它们作为值来构造原始数据对象?
  • @Alcott 如果你是唯一一个读写这些文件的人,那么你可以使用二进制格式,直接读/写结构。但是,要小心指针!编写包含指针的结构会写入实际的指针值,而不是它指向的内容。稍后读取它时,它现在将指向一些未分配的内存区域。此外,在读取和写入字符串时,请考虑终止 '\0' 字符。
  • @Alcott 如果以文本形式编写,您可以使用简单的纯文本、每行一个值或每行带分隔符的多个值(例如 CSV 文件)。或者使用更复杂的格式,如 XML 或 JSON。这完全取决于你。 :)
  • 感谢您的提示。如果我使用二进制模式将这些数据结构写入文件,然后使用文本模式读取文件,我仍然会得到我放入文件中的内容吗?
  • @Alcott 在文本模式下打开文件可能会导致读取或写入文件以对某些字符进行一些“翻译”。最值得注意的是,换行符可以转换为'\n'"\r\n"。因此,如果您在文件中有一些值对应于 `'\n'(十进制 10),那么在读取时您可能会返回两个字节而不是一个字节(13 和 10)。
【解决方案3】:

从历史上看,二进制模式是提供或多或少的透明访问 到底层流;文本模式“规范化”为标准文本 表示,其中行由单个 '\n' 终止 特点。此外,系统可能会对大小施加限制 二进制文件,例如要求它是 128 的倍数或 512 字节。 (第一个是 CP/M 的情况,第二个是许多 DEC OS 的。)文本文件没有这个限制,并且在某些情况下 操作系统强加它,库通常会引入一个额外的 文本文件的文件结束字符。 (即使在今天,大多数 Windows 库在读取文本时识别文件的旧 CP/M 结尾 0x1A 模式。)由于这些考虑,文本模式仅定义在 一组有限的二进制值。 (但如果你将 200 个字节写入二进制文件 文件,当你重新阅读它时,你可能会得到 256 或 512。从历史上看, binary 应该只用于其他结构化的文本,所以 您可以识别逻辑结束,并忽略这些额外的 字节。)

此外,您可以在以二进制打开的文件中任意查找 模式;你只能寻找开始,或者你已经找到的位置 以前记住的,在文本模式下。 (这是因为行结束 映射意味着位置之间没有简单的关系 在文件中,以及在文本流中的位置。)

请注意,这与输出是否被格式化是正交的: 如果您使用<< 输出(并使用>> 输入),则IO 被格式化, 无论打开文件的模式如何。和格式化 是总是文本; iostreams 旨在操纵 文本,并且仅对非文本输入和输出的支持有限。

今天,情况发生了一些变化:在许多情况下,我们期望 我们写是为了让其他机器可读,这假设是一个很好的 定义的格式,可能不是本机使用的格式。 (因此,对于 例如,互联网期望两个字节序列0x0D,0x0A作为一行 结尾,这与 Unix 和许多内部使用的不同 其他操作系统的。)如果可移植性是一个问题,你通常定义一个 格式化,显式编写,并使用二进制模式来确保你的 写的正是所写的;同样在输入上,您使用二进制 格式,并手动处理约定。如果你只是写信给 一个不共享的本地磁盘,但是,文本模式很好,有点 减少工作量。

同样,这两者都适用于文本。如果你想要一个二进制格式,你 必须使用二进制模式,但这还远远不够。你必须 自己实现所有格式化的 IO。在这种情况下,我一般 不要使用std::istreamstd::ostream(其抽象为文本), 而是定义我自己的流类型,源自std::ios_base (对于错误处理约定),并使用std::streambuf(对于 物理 IO)。

最后,不要忽视 all IO 被格式化的事实 方式。只是将一块内存写入文件意味着 格式是当前实现给你的任何东西(它 通常是无证的,这意味着您可能无法 以备将来阅读)。如果您所做的只是溢出到磁盘,并且 唯一一次你会读到它是用同一个程序,用 相同编译器的相同版本,使用相同的编译器选项,然后 你可以只转储内存,只要有问题的内存只是 POD, 并且不包含指针。否则,您必须定义(并记录) 您使用的格式,并实施它。在这种情况下,我建议使用 一种现有的格式,比如 XDR,而不是自己发明:它很多 更容易将“使用 XDR 格式”编写为文档,而不是 描述所有不同的实际位和字节布局 类型。

【讨论】:

  • +1 以获得详细答案,但我不能说我完全理解,:-)。为什么我不能在文本模式下任意搜索?使用seekg(pos),我几乎可以找到文件的每个位置,对吧?
  • @Alcott 因为标准说它是未定义的行为。如果pos 是调用tellg() 返回的值,或者pos0,则没有问题。否则,这是未定义的行为。 (事实上​​,它可以在 Unix 下工作,并且让你稍微领先于你在 Windows 下想要去的地方。在其他操作系统下?谁知道。)\
【解决方案4】:

如果您以文本模式读取/写入文件,则您正在操作文本。它可能是编码错误和特定于操作系统的格式更改的主题,尽管有时它可能工作得很好。但是,在二进制模式下,您不会遇到这些限制。此外,文本模式可能会用\n 字符做一些有趣的事情,例如用\n\r 替换它们。

Fopen 参考例如说:

对于文本文件,取决于文件所在的环境 应用程序运行时,可能会发生一些特殊字符转换 输入/输出操作以使其适应系统特定的文本文件 格式。在许多环境中,例如大多数基于 UNIX 的系统,它 将文件作为文本文件或二进制文件打开没有区别; 两者的处理方式完全相同,但区别在于 推荐用于更好的便携性。

【讨论】:

  • 这种替换会降低一些性能,因为代码必须检查每个字符。
  • @TobiasLangner,所以\n/\r\n 替换会是性能问题?
【解决方案5】:

只有少数操作系统会受到二进制和文本模式之间的选择的影响。 Unix 或 Linux 系统都没有为文本模式做任何特殊的事情——也就是说,文本与二进制相同。

Windows 和 VMS 尤其是在文本模式下转换数据。 Windows 在写入文件时将\n 转换为\r\n,在读取时反之。 VMS 有一个文件记录结构要观察,所以在默认模式下,它会将\n 翻译成记录分隔符。

在不同的地方,二进制更快。如果没有区别,那就没有区别了。

【讨论】:

  • 如果不同,性能差异会很大吗?
  • @Alcott:在一般情况下,我预计性能不会有显着差异。但是,只需大量使用\n 并轻描淡写其他所有内容,就可以很容易地构建一个存在显着差异的测试。在最坏的情况下,Windows 会使写入的数据量翻倍,而 VMS 会疯狂地创建大量记录。
【解决方案6】:

在二进制模式下,您需要使用一个字节大小(考虑 256 ),而在文本模式下,它几乎不超过 100 个字符。显然,存储数据的大小将增加一倍以上。
此外,在某些情况下,您必须遵守结构规范,例如 IPv4 等网络数据包。

举个例子

//No padding
typedef struct abc
{
 int a:4
 char b;
 double c;
} A[]={{.a=4,.b='a',.c=7.45},{.a=24,.b='z',.c=3.2}} ;

在文本模式下存储位字段是不是很困难。显然你会丢失很多东西。

但是,您可以像使用 MIME 一样将数据对象保存为文本格式,但需要额外的例程才能以二进制模式进行转换;性能受到重创。

【讨论】:

  • +1 代码。在您的代码中,您的意思是我最好使用文本模式将A 写入文件?如果是这样,怎么做?只需将每个数据成员的值作为纯文本写入文件,然后将值读回以创建数据对象?
  • :) ,这将是非常困难的,您可以使用一种称为 XML 的方法(如<XML><STRUCT><Instance n="0" type="Text"><val attr="a" bit field="4">4</val></Instance></STRUCT></XML>)以文本模式编写,但最后您必须转换为二进制才能正常操作。在正常的二进制中只需将结构的值转储到文件中即可。在读取操作期间,如果目标结构符合规范,您不必担心如何读取。随着光标向前移动,数组将继续填充。
【解决方案7】:

二进制格式更准确地存储数字,因为它们以精确的内部表示形式存储。保存数据时没有对话,因此保存速度更快。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多