2

我从书中读到这个概念,当我们尝试使用 fputs() 将 \n 写入文件时,fputs() 将 \n 转换为 \r\n 组合,然后如果我们使用 fgets () 读取同一行,则相反转换发生意味着 \r\n 回转换为 \n。我不明白这背后的目的是什么?

4

2 回答 2

3

这是因为 Windows(和 MS-DOS)文本文件应该有以 \r\n 结尾的行,而可移植的 C 程序应该简单地使用 \n,因为 C 最初是在 Unix 上定义的。

并且不只是 fputs 和 fgets 执行此操作 - 文本文件上的任何 I/O 函数,甚至 getc 和 fread,都会执行相同的转换。

于 2013-11-07T15:34:22.793 回答
3

简而言之,DOS就是造成这种情况的原因。

不同的系统对行尾有不同的约定。Unix 认为一个字符 ,'\n'足以标记一行的结尾。DOS 决定它需要两个字符,'\r'并且'\n',尽管其他系统也使用该约定。Mac OS 1-9(Mac OS X 之前)的版本只是用来'\r'代替。其他系统可以使用计数和行数据而不是行结尾,或者可以模拟具有固定长度(72 或 80)的空白的穿孔卡片。Unix 也不区分二进制文件和文本文件。DOS 会。(DOS 也用于Control-Z在文本文件中标记 EOF。Unix 没有 EOF 标记;它确切地知道文件有多大,并使用该长度来确定它何时达到 EOF。)

C 起源于 Unix,但为了更容易在系统之间迁移代码,标准 I/O 包定义当它在处理文本文件时,输入端会将本机行结尾转换为单个'\n'字符以进行统一输入,并且输出端会将 a 转换'\n'为本机行结尾。

然而,提到文本文件也意味着需要有二进制文件,而这些映射不会发生。

您可能会注意到,大多数 Internet 协议(例如 HTTP)都要求 CRLF(回车、换行或'\r', '\n')作为行尾标记。

(其实在 MS-DOS 或 PC-DOS 中指责 DOS 有点不公平。在 DOS 出现之前,还有其他系统使用 CRLF 行结束约定,可能在 Internet 上的影响更大。但是,几乎所有这些祖传系统基本上都已失效,而 Windows 是您现在会遇到的环境,其中二进制文件和文本文件之间的区别很重要,并且您会遇到 CRLF 行结尾。)

请注意,C 标准对文本文件有这样的说法:

ISO/IEC 9899:2011 §7.21.2 文件

¶2 文本流是组成行的有序字符序列,每行由零个或多个字符加上一个终止换行符组成。最后一行是否需要终止换行符是实现定义的。可能必须在输入和输出上添加、更改或删除字符,以符合在主机环境中表示文本的不同约定。因此,流中的字符与外部表示中的字符之间不需要一一对应。只有在以下情况下,从文本流中读取的数据必须与之前写入该流的数据相比较: 数据仅包含打印字符和控制字符水平制表符和换行符;空格字符前面没有换行符;最后一个字符是换行符。读入时是否出现在换行符之前立即写出的空格字符是实现定义的。

很多事情可能会发生也可能不会发生。请特别注意,根据标准,写入文件的尾随空格可能会或可能不会出现在输入中。这允许支持穿孔卡片图像或固定长度记录的系统符合标准。

还要注意(正如Giacomo Degli Eposti所指出的),这一切都意味着,如果您以二进制模式打开一个最初编写为文本文件的文件,您很可能会从 I /O 系统。您会看到每个换行符有两个字符;您可能会看到 aControl-Z后面跟着其他字符(可能是空字节),直到“块”边界,可能是 256 字节的倍数,等等。

于 2013-11-07T15:40:21.287 回答