提问人:Vladlen 提问时间:8/30/2023 最后编辑:genpfaultVladlen 更新时间:8/31/2023 访问量:67
C++ std::fstream getline() 在第一行长行后停止读取文件
C++ std::fstream getline() stops reading file after first long line
问:
我使用 std::fstream 通过成员函数 getline() 逐行读取文本文件。它使用有限大小的缓冲区,有时输入上的行比缓冲区长。第一次读取长行停止读取数据后,调试代码后让我感到惊讶。文档指出,读取长行会设置错误标志,**它被描述为正常情况,而不是运行时错误或致命故障 (https://cplusplus.com/reference/istream/istream/getline/)。文档没有注意到这个标志,也没有描述如何处理长线。getline()
failbit
你知道任何有据可查的方法,如何排长队吗?它应该是,因为这种行为会影响所有类 std::fstream,但我从未看到任何描述或讨论。
程序示例:
#include <fstream>
#include <iostream>
#include <string>
int main(){
char buffer[10];
std::string filename{"test.txt"};
auto file=std::fstream(filename, std::ios_base::in | std::ios_base::binary );
if(file.is_open()){
size_t readBites{4};
file.getline(buffer,readBites);
auto length=std::strlen(buffer);
auto lengthStream=file.gcount();
std::cout << "Read "<<length<<"/"<<lengthStream<<":"<<buffer<<std::endl;
file.getline(buffer,readBites);
length=std::strlen(buffer);
lengthStream=file.gcount();
std::cout << "Read "<<length<<"/"<<lengthStream<<":"<<buffer<<std::endl;
}
return 0;
}
如果 test.txt 文件包含,例如:
1234567890
ABCDEFGHIJK
我期望输出(如在 C 中):fgets(...)
Read 3/3:123
Read 3/3:456
但它确实是:
Read 3/3:123
Read 0/0:
我使用有限大小的缓冲区,因为这是客户端软件的要求,调用此代码,它可以是任何大小,并在短缓冲区中处理长行。
答:
正如您链接到的文档所说:
如果函数未提取任何字符,或者一旦 (n-1) 个字符已写入
s
,则未找到分隔符,则设置 failbit 标志。
因此,如果尝试读取的数据超过缓冲区可以容纳的数据,则会设置流的状态:failbit
要么未找到分隔字符,要么根本没有提取任何字符(因为文件末尾在第一个字符之前,或者因为构造失败)。
sentry
此时,流将不再读取任何数据:
在内部,该函数通过首先构造一个对象(设置为 true)来访问输入序列。然后(
如果好
),它从其关联的流缓冲区对象中提取字符,就像调用其成员函数或 一样,最后在返回之前销毁该对象。sentry
noskipws
sbumpc
sgetc
sentry
由于流不再处于状态,因此它会停止提取字符。您必须清除()
流才能将其恢复到状态。good
good
评论
if (file.getline(...
istream
failbit
readline()
catch()
!file.readline()
failbit
clear()
fstream
catch()
评论
std::string
有一个getline
版本,它为整行分配内存,对吧?已提取 count - 1
个字符,则调用SetState(failbit)。
std::ios_base::binary