可移植行结束符(换行符)

Portable end of line (newline)

本文关键字:换行符 结束 可移植      更新时间:2023-10-16

这是一个令人不快的惊喜,'n'取代了"rn"在Windows上,我不知道。(我猜它也被替换在Mac上…)

是否有一种简单的方法来确保Linux, Mac和Windows用户可以轻松地交换文本文件?

我的意思是:不以二进制模式编写文件或自己测试和替换行尾字符(或使用一些第三方程序/代码)。这个问题影响了我的c++程序执行文本文件I/o。

为与其他答案部分重叠而道歉,但为了完整性:

误解: endl '更可移植',因为它根据平台约定编写行结束符。

真相: endl定义为将n写入流,然后调用flush。所以实际上你几乎不会想用它。无论您使用的是os<<endlos<<'n'还是fputs("n",file),所有写入文本模式流的n都会在后台被CRT隐式地转换为rn

误解:你应该以文本模式打开文件来写文本,以二进制模式打开文件来写二进制数据。

真相:文本模式之所以存在,首先是因为以前的文件系统区分了文本文件和二进制文件。在我所知道的任何一个平台上都不再是这样了。您也可以将文本写入二进制打开的文件,您只是失去了自动的n ->rn在Windows上的转换。然而,这种转换弊大于利。除此之外,它使您的代码在不同的平台上表现不同,并且tell/seek的使用变得有问题。因此,最好使用避免这种自动转换。请注意POSIX 区分二进制模式和文本模式。

如何做文本:在二进制模式下打开所有内容,并使用普通的n。您还需要考虑编码问题。标准化UTF-8以确保unicode的正确性。在内部使用UTF-8编码的窄字符串,而不是wchar_t,这在不同的平台上是不同的。您的代码将变得更容易移植。

提示:可以强制MSVC默认以二进制模式打开所有文件。它应该是这样工作的:

#include <stdio.h>
#include <iostream>
int main() {
    _fmode = _O_BINARY;
    std::ofstream f("a.txt"); // opens in binary mode
}

EDIT:截至2021年,Windows 10记事本可以理解UNIX行结束符。

问题根本不在于endl,而是文本流根据系统的标准重新格式化换行符。

如果你不想这样,干脆不要使用文本流——使用二进制流。也就是说,打开带有ios::binary标志的文件。

也就是说,如果唯一的问题是用户可以交换文件,我根本不会为输出模式而烦恼,我宁愿确保您的程序可以读取不同的格式而不会阻塞。也就是说,它应该接受不同的行尾。

这是任何体面的文本编辑器所做的(但是,Windows上的默认notepad.exe而不是一个体面的文本编辑器,并且不能正确处理Unix换行符)。

如果你真的只想要一个ASCII LF,最简单的方法是以二进制模式打开文件:在非二进制模式下,n被特定平台的行尾序列替换(例如,它可能被LF/CR或CR/LF序列替换;在unix上,它通常只是LF)。在二进制模式下不会这样做。关闭替换也是二进制模式的唯一效果。

顺便说一句,使用endl相当于写一个n,然后刷新流。通常的非预期刷新会成为主要的性能问题。因此,endl应该很少使用,并且只在需要刷新时使用。