2

为什么Windows“记事本”无法读取特定的“新行”而“记事本++”可以读取它们?

好吧,这不是问题。我的问题是“std::ifstream::getline”,它读取所有内容,直到遇到“那些只能被 windows 记事本识别的新行”,例如:“windows notepad”将如下所示:

12345
67890

notepad++ 的内容如下:

1
2
3
4
...

而“std::ifstream::getline”会得到“12345”?!!!

我需要通过 std::fstream 解析 csv 文件,而 csv 新行就像 notepad++ 的新行。那么,是否有任何功能或制作可以读取这些新行的通用功能?

4

3 回答 3

9

有 3 种常见的行尾样式,由\n("line-feed", or "newline") 和\r("carriage return") 字符组成:

  • \r\n: 窗户风格
  • \n:UNIX风格(包括Mac OSX)
  • \r: Mac 风格 (pre-OSX)

几乎每个处理文本的程序都会接受其中任何一个作为换行符。我说几乎是因为本机 Windows 控件没有。记事本只是包装在窗口框架中的 Win32 文本区域控件。这意味着在 win32 中使用文本时,您必须手动使用 Windows 样式的行尾。不仅是记事本,而且如果您在 Win32 弹出窗口中有一个多行字符串,例如,您必须确保使用\r\nelse,您将在一行中获得所有内容。

大多数优秀的文本编辑器都会在某处设置保存时使用的行尾。还有一些命令行实用程序,例如dos2unixunix2dos将文本文件从一个文件转换为另一个文件。


历史注释:

当终端只是一台电子打字机时,ASCII 和文本终端就出现了。回车 (CR) 字符\r意味着将打印机回车放回同一行的开头。换行(LF) 字符\n意味着将纸张向上移动一行。Windows 的理念是,要开始新行,您必须同时执行以下两项操作:CR LF。

于 2013-09-20T00:40:47.123 回答
4

首先,只有一种换行符:'\n'. 但是,在系统上,行结束序列由换行符"\n\r"和回车符("\r\n"行,但否则停留在该位置并发送回车会将头部移动到行的开头)。从外观上看,您有一个使用换行符和回车符用于不同目的的文件,但以文本模式读取文件会混淆行序列的结尾。部分谜团可能可以通过以二进制模式打开文件来解决,即std::ios_base::binary在打开文件时添加标志。

但是,这不会改变 的行为std::getline():此函数最多读取第一行终止字符,默认情况下是换行符 ( '\n')。要读取不同字符的行,您可以将其作为附加参数传递(我使用的是非成员函数,因为它处理任意长字符串而不是成员函数读取char数组;成员函数可以类似地使用):

std::ifstream in("file.csv", std::ios_base::binary);
for (std::string line; std::getline(in, line); ) {
    std::istringstream sin(line);
    for (std::string field; std::getline(sin, field, '\r'); ) {
        std::cout << "field='" << field << "'\n";
    }
}

根据您的描述,您的文件似乎'\r'用作字段分隔符。通过以二进制模式打开文件然后打印各个字符及其各自的代码,这可能是最容易找到的不同之处:

std::ifstream in("file.csv", std::ios_base::binary);
for (std::istreambuf_iterator<char> it(in), end; it != end; ++it) {
    std::cout << std::setw(3)
              << int(static_cast<unsigned char>(*it)) << ' ' << *it << '\n';
}

这只会打印每个字符的代码和字符本身。您应该能够找到字段分隔符的值,但我猜'\r'正在使用。

于 2013-09-20T00:32:09.553 回答
0

不同的平台对于如何在文本文件中指示行尾有不同的约定。当您\n在程序中编写字符时,您是在要求标准库写入或读取构成系统行尾的任何字符. 如果您有一个使用标准工具在一个系统上编写的文本文件,并且您将它移动到另一个系统,您必须更改行尾以匹配新系统。文本模式下的 FTP 将执行此操作。如果您只是复制字节,则可能会产生不遵守本地约定且无法读取的文本文件的风险。(尝试在 Unix 系统上通过 gnu make 运行 Windows 生成的 makefile...)。一些标准库比其他标准库更擅长整理非常规文件,但如果您需要将文本文件从一个系统移动到另一个系统,则需要遵守本地约定并在程序之外进行适当的转换。

于 2013-09-20T11:12:51.777 回答