我们会经常用到getline()函数,去从流中读取指定的一行内容。尤其是在牛客或者leetcode上刷题的同学,应该更为熟悉这个用法。但是通过这篇文章,你可能会发现你根本没有那么了解getline()这个函数。
问题起因:
今天在写项目的时候用到了C++ifstream流,利用它来读取指定文件的内容。我的读取文本如下:
我的预期是这样的:利用getline()一行一行的读文件,以空行作为界限,每一个小段做一个处理。
vector<string>v;
for(int i=0;i<2;++i){
v.clear();
while( getline(in,str) ){ //读到空行的时候就跳出循环
//一行一行读
v.push_back(str);
}//end of while
//把下一行的空行读走;铺垫下一个host列表 咦,好像这里不用再操作了,空行已经被读走...
Print(v);
简单的实现,感觉代码没有任何问题。不过就是这简单的操作却让人伤神了半天。 注意我的for循环是循环两次,按照预期,当读入空行时,getline()返回0,判断为假跳出循环,那么应该是会读入文本的前两段然后Print()打印。但是结果却是:文本内容全部打印! 我真的是懵逼,在风中凌乱。。。这么简单的几行代码也会出错,我哭/(ㄒoㄒ)/~~
上网百度getline()的用法,发现好像也没有错误呀:
函数声明:
ssize_t getline(char **lineptr, size_t *n, FILE *stream);
返回值
成功:返回读取的字节数。
失败:返回-1。
读到空行返回值不是为0吗,但是为什么却没有按照预期跳出循环呢,我再哭/(ㄒoㄒ)/~~
最后,当我看到了 basic_istream::getline()这个概念,才猛然醒悟 —— 我们一般用的getline()是C++库里处理string流的getline(),而在项目中用到的文件ifstream读取的getline()是处理isream流的getline()。 这两个getline()原来是有区别的。 来看一下C++reference标准里边的后者返回值的定义:
额emm…,看不懂英文没关系,我来总结:在后者也就是处理istream流额时候,getline()的返回值是这样的:
只要可以读到文件内容(包括空行),返回值就一直是True. 如果读取失败,那么会抛出相对应的异常。
所以在我上述项目中的情境下,while()判断其实一直是true,因为一直都有读到内容,所以外层for循环其实是没有限制力的/(ㄒoㄒ)/~~ 所以如果要达到之前的预期,需要在循环体内手动的进行空行的判断:
for(int i=0;i<2;++i){
v.clear();
while( getline(in,str) ){ //读到空行的时候就跳出循环
if(str.size()==0)
break;
//一行一行读
v.push_back(str);
}//end of while
ok,这个故事告诉我们做学问还是不能一知半解,努力吧少年(ง •_•)ง