【问题标题】:Cross-platform newline confusion跨平台换行混淆
【发布时间】:2011-12-23 10:52:33
【问题描述】:

由于某种原因,我的写入文本文件功能突然停止工作。

void write_data(char* filename, char* writethis)
{
    ofstream myfile;
    myfile.open (filename, std::ios_base::app);
    myfile << endl << writethis;
    myfile.close();
}

该函数是从一个循环中调用的,所以基本上它以一个空行开始,并将所有以下“writethis”行附加到一个新行上。

然后突然之间,不再有换行符。所有文本都附加在一行上。所以我做了一些挖掘,我发现了这个:

  1. Windows = CR LF
  2. Linux = LF
  3. MAC

所以我把行改为

myfile << "\r\n" << writethis;

它又起作用了。但现在我很困惑。我在 linux 上进行编码,但在使用 filezilla 传输它们之后,我正在读取使用该程序创建的文本文件在 windows 上。现在是哪一部分导致文本文件中的行显示为一行?

我很确定“endl”在 linux 上工作得很好,所以现在我认为 windows 把文件弄乱了用 filezilla 传输它们之后?弄乱文本文件的写入(和读出)方式将保证我的程序会中断,所以如果有人能解释这一点,我将不胜感激。

我也不记得我在我的程序中做了什么改变导致它中断,因为它之前工作得很好。我唯一添加的是线程。

编辑: 我曾尝试从 ASCII / Binary 交换传输模式(甚至删除了 force-ASCII-for-txt-extension),但没有区别。换行符出现在 linux 中,但不在 Windows 中。

多么奇怪。

【问题讨论】:

  • 十亿个关于行尾的问题的重复。
  • @TomalakGeret'kal 那为什么我的搜索没有弹出?
  • 因为你没有正确搜索?
  • 为每一行输出重新打开和重新关闭文件效率低下。无论如何,函数体可以更简单地写成ofstream(filename, std::ios_base::app) &lt;&lt; endl &lt;&lt; writethis;。这充分利用了 RAII。此外,您确实应该使用std::string 来表示文本项。

标签: c++ c text newline


【解决方案1】:

发生的情况是,您编写了 Unix 行尾 ('\n'),然后将其传输到 Windows 机器,得到一个按位相同的文件,然后尝试使用不理解 Unix 行尾的查看器打开文件 (可能是记事本)。

根据我编写可移植代码的经验:

  • 在所有平台上标准化一个行尾('\n',LF)。
  • 始终以二进制文件打开文件,即使您编写文本也是如此。
  • 让打开文件的用户使用能够理解任何行尾的文本查看器。 Windows 有很多(包括 Visual Studio、Notepad++、写字板和您喜欢的浏览器)。

是的,我确实认为standardize on one thing 对每个人都有更多的好处,而不是在任何地方都支持他们。我也否认存在“适当平台上的适当行尾”。微软决定他们的原生 API 不说 UTF-8 或不理解 Unix 行尾这一事实并不能阻止每个人的代码在 Windows 上这样做。只要确保不要将这些东西传递给 WinAPI。很多时候,您对系统永远看不到的内部数据进行文本处理,那么您为什么需要通过满足这些系统内部的期望来使您的生活复杂化呢?

【讨论】:

  • 这当然可以根除问题,但期望任意用户为此做好准备有点难度,并且通过回避问题根本无法解决问题。正确的方法是修复文件传输,以便您在正确的平台上拥有正确的行尾。好消息是,这并不难!
  • @TomalakGeret'kal:这是不可能的,您通常无法确定什么文件是文本文件,什么文件是二进制文件。现在想象两台机器,一台 Linux 和一台 Windows 写入 NAS 上的同一个文件。谁负责以及负责什么转换?
  • @ybungalobill:如果你是唯一一个写文件的人,那就太好了。不幸的是,您必须处理由其他程序编写的文件(这里我们肯定有 filezilla 可能还有其他可能编写文件的文本编辑器(以读取的修改格式))。因此,您确实需要详细解释正在发生的事情,以便 OP 可以考虑这些其他程序并进行适当的补偿。尽管我同意您的小规模技术,但对于 OP 将遇到的一般情况,信息不足。
  • @ybungalobill:如果 OP 不知道他面前的文件格式是什么,那么会有很多更大的问题。
  • @TomalakGeret'kal:您说的是“任意用户”和“文件传输”,OP 也不是。
【解决方案2】:

在内部,所有应用程序都使用“\n”来表示行终止。

问题在于行终止顺序是特定于文本文件的平台(正如您的研究结果) 注意:文本文件,这是您打开文件时的默认格式。如果您在打开文件时显式选择二进制文件,则在读取/写入时不会发生翻译。

这实际上意味着当您将“\n”字符写入文件时,它会转换为特定于平台的字符序列。但还要注意,当读取文件时,这个特定于平台的序列会转换回 '\n'。您遇到的问题是您在一个平台上编写文件并在另一个平台上读取它们。

在 linux 上,行终止序列是 LF ('\n')。因此,您编写文件并将所有 '\n' 转换为 'LF' 字符。您将这些文件传输到 Windows 系统,然后读取该文件。在 Windows 上,行终止序列是 'CRLF' 所以读取文件的编辑器正在寻找两个字符以转换回 '\n' 但没有找到这些字符。现在取决于编辑器的智能程度,你得到的是单行还是多行。

【讨论】:

    【解决方案3】:

    endl 确实“在 Linux 上工作得很好”。流式传输 endl 流式传输 \n 字符并刷新流。总是。

    但是,文本模式下的文件流会在 Windows 的实现层将此 \n 转换为 \r\n,并且您经常会发现在平台之间传输文件时也会转换行尾。

    这可能不是 C++ 问题,没有什么是“坏”的;您可能应该将 FileZilla 配置为将您的文件视为 text 而不是“binary”(一种不转换行尾的模式)。如果您的文件没有像“.txt”这样的扩展名,那么默认情况下它可能不会这样做。

    【讨论】:

    • 另外两个人建议我以二进制形式打开,而你建议我以文本形式打开。两者都不起作用,但这只会增加混乱。
    • @natli 你还没有尝试做我的第三个子弹,所以不要说它不起作用。实际上,当您在共享存储上打开文件时,这是您唯一的选择。最后,重要的是您使用什么查看器,而不是具体写什么。
    • 换行符显示在程序员的记事本中,但不在记事本中。我觉得这很奇怪,它可能会引起混乱。我以为我确实通过尝试二进制和 ASCII 来完成您的第三个项目?我不介意让它休息,但我确实觉得这很奇怪。
    • @natli:没什么奇怪的。 Microsoft Notepad 作为文本查看器是个笑话。它只懂\r\n,不能处理大文件等等……那又怎样?只是不要使用它。我的第三个项目符号没有说明二进制和 ASCII。
    • @ybungalobill 好吧,如果没有办法为记事本修复它,那么我想就是这样。
    【解决方案4】:

    如果您以 ASCII 格式传输文件,FTP 可能会弄乱您的文件(也就是说,它会转换换行符)。尝试以 BIN(二进制)传输。

    【讨论】:

    • 恰恰相反。问题是行尾没有为他的平台转换,他希望它们在哪里。
    • 取决于他想要什么。我总是尝试自己做换行符转换——自动转换通常只会增加混乱……写文本,以二进制格式传输,读取文本。它将采用与编写时相同的格式。如果您仍然遇到换行问题,您可以解决一个较小的问题。
    • 实际上,ybungalobill 总结得很好。 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-14
    • 1970-01-01
    相关资源
    最近更新 更多