C++ 如何到达文件末尾
我有一个函数,它从文件中获取一些信息并将其放入一个结构中。我设置了一个循环(分别为和设置和设置和设置,条件是循环一直持续到文件末尾。 但它不起作用C++ 如何到达文件末尾,c++,file,struct,C++,File,Struct,我有一个函数,它从文件中获取一些信息并将其放入一个结构中。我设置了一个循环(分别为和设置和设置和设置,条件是循环一直持续到文件末尾。 但它不起作用 void FileToStructProfessors() { int n; fstream CurrentFile("professor.txt"); if (!CurrentFile) { cout <<"can't open file"; } else
void FileToStructProfessors()
{
int n;
fstream CurrentFile("professor.txt");
if (!CurrentFile)
{
cout <<"can't open file";
}
else
{
CurrentFile.seekp(5);
/*for(n=0;CurrentFile.eof();n++)
{
CurrentFile>>P1[n].FirstName;
CurrentFile>>P1[n].LastName;
CurrentFile>>P1[n].PID;
CurrentFile>>P1[n].Major;
CurrentFile>>P1[n].Level;
CurrentFile.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
cout<<P1[0].FirstName<<endl;
}*/
n=0;
while(!CurrentFile.eof())
{
CurrentFile>>P1[n].FirstName;
CurrentFile>>P1[n].LastName;
CurrentFile>>P1[n].PID;
CurrentFile>>P1[n].Major;
CurrentFile>>P1[n].Level;
CurrentFile>>P1[n].Date;
CurrentFile.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
cout<<P1[3].FirstName<<endl;
n++;
}
}
CurrentFile.close();
}
针对教授结构
struct Professors
{
string FirstName,LastName;
long long int PID;
string Major,Level,Date;
}P1[100];
您的问题是,您正在尝试读取行,但是
CurrentFile>
忽略了所有的空白,包括空格。所以当你读到第一位教授时:
med
hamidi
1001
civil
associate professor
91/02/15
您将获得:
FirstName = med
LastName = hamidi
PID = 1001
Major = civil
Level = associate
Date = professor
“associate”和“professor”之间有一个空格,因此CurrentFile>>P1[n]。Level
只选择“associate”,因为CurrentFile>
看到了空格并停止。然后,你的下一个CurrentFile>>
选择“professor”,而不是你想读的日期。对整个文件进行复合,您将得到大量没有意义的输入
您可以使用getline(当前文件,*要读取的字符串*)
解决此问题,如以下示例所示。请注意,这不是生产质量代码,只是一个简单的玩具示例,演示了getline
,旨在帮助您推进项目
void FileToStructProfessors()
{
int n;
fstream当前文件(“professor.txt”);
if(CurrentFile.fail())
{
cout>P1[n].PID;
getline(当前文件,P1[n].Major);
getline(当前文件,P1[n].Level);
getline(当前文件,P1[n].日期);
这是读过去的空白行。
//分隔您的条目。
getline(当前文件,s);
//印刷品。
n++;
}
}
CurrentFile.close();
}
顺便说一下,我删除了:
CurrentFile.seekp(5)
CurrentFile.ignore(std::numeric_limits::max(),'\n')代码>
struct Professors
{
string FirstName,LastName;
long long int PID;
string Major,Level,Date;
}P1[100];
我的示例不安全/不正确,因为那些
getline
调用或CurrentFile>
语句中的任何一个都可能遇到错误,并且不会检查它们是否有错误。我写这篇文章是为了相对简单地解释为什么代码出现问题。对于安全/正确的代码,请查看。执行输入的条件不应以获取文件结尾为前提。仅在输入失败之前执行输入是执行提取的常规条件。否则会导致不必要的行为
因此,您应该检查流是否没有设置std::ios_base::failbit
或std::ios_base::badbit
。检查这两个位是必要的,因为failbit
表示流无法成功提取的解析错误,badbit
表示外部设备有问题(可能是不可恢复的错误)。两者都会导致提取失败。但这一切都需要在尝试输入后完成
以下是使用您的代码表示的上述任务:
请注意,我还通过使用std::getline()
更改了最后两个提取。这是因为文件中的相应数据包含格式化运算符用作分隔符的空格。日期使用斜杠,当使用格式化输入时,斜杠也会被分隔。然后,级别
和日期
数据成员必须是std::string
s,并且需要使用无格式输入
如果任何一个提取失败,流将设置适当的位。然后,流将使用运算符bool()
(或运算符void*()
pre-C++11隐式转换为布尔值,随后将升级为布尔值)。布尔运算将使用检查流状态!此->fail()
(同时检查badbit
和failbit
),如果函数返回true,则整个while
循环表达式为false,并且不会执行剩余的提取(因为短路计算)
如果流仍处于良好状态(!this->fail()
返回true
),则将执行循环体。如果流在执行提取时遇到EOF字符,将设置eofbit
,但循环不会停止,直到稍后尝试的输入操作未能成功提取。这是理想的行为。改进您的程序:
那是你问题的症结所在。您不了解流输入是如何执行的。我不知道是谁教你,而(!file.eof())
,但这几乎总是错误的
你的程序很好,但并不完美。如果你想知道如何改进你的程序,请继续阅读,否则我希望我的其他答案会有所帮助
您没有向我们显示相关的代码,但我假设P1
是一个默认大小的静态数组(该大小为4)。由于索引n
随着文件内容的增加而增加,因此您的代码具有潜在的危险性。如果要提取到数组中的数据超过4个“组”,则程序将调用未定义的行为
为了避免这个潜在问题,可以使用动态容器,如std::vector
。它将分配一个适当大小的内部数组,并根据需要动态调整大小。可以按如下方式指定构造时的尺寸:
上面的代码出现在您的while循环中(我相信),试图丢弃空格和换行符,以便可以提取的下一个字符是下一位教授的名字。出于上述相同的原因,不需要这样做
最后,为了便于提取到
Project
类型的对象中,建议您使用运算符重载实现自己的提取程序。它保持
void FileToStructProfessors()
{
int n;
fstream CurrentFile("professor.txt");
if (CurrentFile.fail())
{
cout <<"can't open file";
// Put a return here so you don't
// try to `.close()` the file later.
return;
}
else
{
while(CurrentFile.good())
{
getline(CurrentFile, P1[n].FirstName);
getline(CurrentFile, P1[n].LastName);
// PID is an integer, and getline doesn't work with integers,
// only strings. You can try simply 'CurrentFile >> P1[n].PID;',
// but this will mess up the next getline (try it yourself if you
// want). We can get around this using a stringstream, so put
// '#include <sstream>' at the top of your file.
string s;
getline(CurrentFile, s);
istringstream iss(s);
iss >> P1[n].PID;
getline(CurrentFile, P1[n].Major);
getline(CurrentFile, P1[n].Level);
getline(CurrentFile, P1[n].Date);
// This is to read past the blank line that
// separates your entries.
getline(CurrentFile, s);
// Print stuff.
n++;
}
}
CurrentFile.close();
}
while ( CurrentFile >> P1[n].FirstName &&
CurrentFile >> P1[n].LastName &&
CurrentFile >> P1[n].PID &&
CurrentFile >> P1[n].Major &&
std::getline(CurrentFile >> std::ws, P1[n].Level) &&
std::getline(CurrentFile >> std::ws, P1[n].Date) )
CurrentFile >> size;
std::vector<Professor> P1(size);
CurrentFile.ignore(std::numeric_limits<std::streamsize>::max(), '\n');