为什么当我们在文件中写入\ n时它转换成\ r \ n组合?

时间:2013-11-07 15:31:37

标签: c newline fgets fputs

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

2 个答案:

答案 0 :(得分:3)

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

这不仅仅是fputs和fgets这样做 - 文本文件上的任何I / O函数,甚至是getc和fread,都将进行相同的转换。

答案 1 :(得分: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包定义了当它处理文本文件时,输入端会将本机行结尾转换为单{{ 1}}用于统一输入的字符,输出端将'\n'转换为本机行结尾。

但是,提及文本文件也意味着需要二进制文件,这些映射不会发生。

您可能会注意到,大多数互联网协议(例如,HTTP)都要求行标记的CRLF(回车,换行或'\n''\r')。

(实际上,指责DOS,如在MS-DOS或PC-DOS中,有点不公平。在DOS存在之前,还有其他系统使用CRLF线路终端约定,它们可能在互联网上更有影响力。但是,几乎所有这些祖先系统都基本上都不存在了,而Windows是你现在遇到的环境,二进制和文本文件之间的区别很重要,而且你会遇到CRLF行结尾。)

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

ISO / IEC 9899:2011§7.21.2文件

  

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

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

请注意(正如Giacomo Degli Eposti所指出的),这一切意味着如果你打开一个最初写成文本文件的二进制模式的文件,你可能会得到一个明显不同的列表从I / O系统返回的字节数。你会看到每个换行符有两个字符;您可能会看到 Control-Z 后面跟着其他字符(可能是空字节),直到'block'边界,可能是256字节的倍数等等。