【问题标题】:why when we write \n in the file it converts into \r\n combination?为什么当我们在文件中写入 \n 时它会转换为 \r\n 组合?
【发布时间】:2013-11-07 15:31:37
【问题描述】:

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

【问题讨论】:

  • 一个字符是“换行”,另一个是“回车”;可以追溯到行式打印机时代的术语。这两个字符都是必需的,因为单独换行会在不改变列的情况下将纸张移动一行,而回车会在不改变行的情况下改变到最左边的列。
  • 我理解这个问题,但我不相信这个说法是真的。例如,如果您编写一个带有单个 '\n' 的文件,则该文件的长度为 1。也许在某些 windows 世界里,书上说的是真的,但在普通的 unix 世界里却不是。

标签: c newline fgets fputs


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    简而言之,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 包定义当它处理文本文件时,输入端会将本机行转换为单个 @987654326 @ 字符用于统一输入,输出端会将'\n' 转换为本机行结尾。

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

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

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

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

    ISO/IEC 9899:2011 §7.21.2 文件

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

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

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

    【讨论】:

    • 另外请注意,如果在 Windows 机器上,您以“文本模式”写入文件并以“二进制模式”重新打开同一个文件,您将读取两个不同的字符(即您读取实际写入文件的字节数)
    • 所以这个环境中的 main() { printf("\n") } 会导致文件大小为 2?奇怪的。但是 stdio 足够聪明,即使在不同环境之间它也大多会消失?
    • @CharlieBurns:是的,因为一个空行的文本文件大小为 2 个字节。
    • \n 和 \r\n 不是唯一的行尾表示。 OSX 之前的 MacOS 使用 \r。其他系统不一定使用字符序列来表示行尾;他们可能会使用某种记录结构(VAX/VMS、IBM 大型机等)。
    • @Jonathan 您是如何输入 Control-Z 字形使其看起来像一个键的?
    猜你喜欢
    • 2018-08-31
    • 2011-02-07
    • 1970-01-01
    • 2016-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多