13

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

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

4

7 回答 7

21

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

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

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

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

于 2012-08-16T06:09:41.523 回答
7

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

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

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

于 2012-08-16T06:04:13.963 回答
7

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

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

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

今天,情况发生了一些变化:在许多情况下,我们希望我们编写的内容可以从其他机器上读取,这假设了一种定义明确的格式,而这可能不是本机使用的格式。(因此,例如,Internet 期望两个字节序列 0x0D、0x0A 作为行结尾,这与 Unix 和许多其他操作系统内部使用的不同。)如果考虑可移植性,通常定义格式,写它明确地,并使用二进制模式来确保您所写的正是所写的;同样在输入上,您使用二进制格式,并手动处理约定。但是,如果您只是写入未共享的本地磁盘,则文本模式很好,并且工作量少一些。

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

最后,不要忽视一个事实,所有IO 以某种方式格式化。只需将一块内存写入文件就意味着格式是当前实现给您的任何格式(通常没有记录,这意味着您将来可能无法读取它)。如果您所做的只是溢出到磁盘,并且您唯一一次阅读它是使用相同的程序,使用相同编译器的相同版本编译,使用相同的编译器选项,那么您可以只转储内存,前提是有问题的内存只是 POD,不包含指针。否则,您必须定义(并记录)您使用的格式并实施它。在这种情况下,我建议使用现有格式,例如 XDR,而不是自己发明:将“使用 XDR 格式”编写为文档要容易得多,

于 2012-08-16T08:14:53.777 回答
3

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

例如,Fopen参考说:

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

于 2012-08-16T06:03:12.433 回答
2

在二进制模式下,您需要使用一个字节大小(考虑 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 一样将数据对象保存为文本格式,但需要额外的例程才能以二进制模式转换;性能受到重创。

于 2012-08-16T06:11:59.930 回答
2

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

Windows 和 VMS 尤其是在文本模式下转换数据。Windows在写入文件时转换\n为,在读取时转换为相反。\r\nVMS 有一个要观察的文件记录结构,因此在默认模式下,它转换\n为记录分隔符。

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

于 2012-08-16T06:07:58.560 回答
0

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

于 2016-09-09T13:32:26.987 回答