为什么windows“notepad”无法读取特定的“新行”而“notepad ++”可以读取它们?
好吧,那不是问题。我的问题是“std :: ifstream :: getline”读取所有内容,直到它遇到“那些只能被Windows记事本识别的新行” 例如: “windows notepad”的内容如下:12345
67890
notepad ++将如下所示:
1
2
3
4
...
和“std :: ifstream :: getline”会得到“12345”?!!!
我需要通过std :: fstream解析csv文件,而csv新行就像记者++新行一样。那么,是否有任何功能或制作可读取这些新行的通用功能?
答案 0 :(得分: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'
。
答案 1 :(得分:3)
有3种常见的行结尾样式由\n
(“换行”或“换行”)和\r
(“回车”)字符组成:
\r\n
:Windows风格\n
:UNIX样式(包括Mac OSX)\r
:Mac风格(OSX之前)几乎每个处理文本的程序都会接受其中任何一个作为换行符。我说几乎是因为原生Windows控件没有。记事本只是一个包含在窗口框架中的Win32文本区域控件。这意味着在使用win32文本时必须手动使用Windows样式的行结尾。不仅仅是记事本,而且如果你在Win32弹出窗口中有一个多行字符串,你必须确保使用\r\n
否则你将获得一行中的所有内容。
大多数优秀的文本编辑器都会在某个位置设置保存时结束使用的行。还有一些命令行实用程序,如dos2unix
或unix2dos
,可以将文本文件从一个文件转换为另一个。
历史记录:
当终端只是一台电子打字机时,就会出现ASCII和文本终端。回车(CR)字符\r
表示将打印机托架放回同一行的开头。换行(LF)字符\n
意味着将纸张向上移动一行。 Windows的理念是,要开始一个新行,你必须同时做到这两点:CR LF。
答案 2 :(得分:0)
不同的平台对文本文件中的行结尾有不同的约定。当您在程序中编写字符\n
时,您要求标准库编写或读取包含在系统上结尾的行的任何字符。如果您有一个在一个系统上使用标准工具编写的文本文件,并将其移动到另一个系统,则必须更改行结尾以匹配新系统。文本模式下的FTP将执行此操作。如果您只是复制字节,则存在文本文件不符合本地约定且无法读取的风险。 (尝试在Unix系统上通过gnu make运行Windows生成的makefile ...)。有些标准库比其他文件更好地整理非常规文件,但如果您需要将文本文件从一个系统移动到另一个系统,则需要遵守本地约定并在程序之外进行正确的转换。