ifstream仅读取3次数据:性别统计与GPA计算异常排查
问题描述
我编写了一段C++代码,用于统计不同性别的人数、GPA总和及GPA平均值。男女统计的逻辑几乎完全一致,但第二次循环无法从文件中读取任何数据。我尝试交换男女统计的顺序,结果发现无论哪部分放在第二位,都无法完成统计。代码会输出“File Opened”,说明文件已成功打开,但我无法理解为何无法多次遍历文件内容。附上代码及输出情况:
#include<iostream> #include<iomanip> #include<fstream> using namespace std; void openFiles(ifstream& read, ofstream& write) { read.open("StudentsPreformanceData.txt"); if (read.is_open()) cout << "File Opened" << endl; else cout << "Error try again"; write.open("Results.txt"); write << fixed << showpoint << setprecision(2); } void initialize(int& countFemale, int& countMale, double& sumFemale, double& sumMale) { countFemale = 0; countMale = 0; sumFemale = 0.00; sumMale = 0.00; } void sumGrades(ifstream& read, double& sum, char gender) { char student; double grade; while (!read.eof()) { read >> student; read >> grade; if (student == gender) sum = sum + grade; //cout << student << " " << grade << " " << sum << endl; } read.close(); } double averageGrades(ifstream& read, double sum, int& count, char gender) { char student; double grade; while (!read.eof()) { read >> student; read >> grade; if (student == gender) { count = count + 1; } cout << student << " " << count << " " << sum << endl; } return sum / count; read.close(); } void printResults() { } int main() { ifstream read; ofstream write; openFiles(read, write); int countFemale, countMale; double sumFemale, sumMale; initialize(countFemale, countMale, sumFemale, sumMale); cout << countFemale << sumFemale << countMale << sumMale << endl; sumGrades(read, sumFemale, 'f'); cout << countFemale << " " << sumFemale << " " << countMale << " " << sumMale << endl; openFiles(read, write); sumGrades(read, sumMale, 'm'); cout << countFemale << " " << sumFemale << " " << countMale << " " << sumMale << endl; openFiles(read, write); averageGrades(read, sumMale, countMale, 'm'); cout << countFemale << " " << sumFemale << " " << countMale << " " << sumMale << endl; openFiles(read, write); averageGrades(read, sumFemale, countFemale, 'f'); cout << countFemale << " " << sumFemale << " " << countMale << " " << sumMale << endl; }
输出显示多次打印“File Opened”,但后续统计的数值未更新,第二次及之后的循环没有读取到任何数据。
问题原因及解决方法
核心问题
- 文件流状态未重置:第一次读取文件后,文件指针移到末尾,流的
eof标志被置位。即使重新调用openFiles,流对象仍处于错误状态,不清除标志的话无法正常读取。 read.close()位置错误:averageGrades函数中,read.close()写在return语句之后,永远不会执行,导致流资源无法正确释放。- 重复IO效率低下:多次打开关闭文件不仅效率低,还容易引发流状态异常,更合理的方式是一次性读取数据到内存再统计。
修复方案
方案1:修复流状态,正确重复打开文件
修改openFiles函数,先清除旧流的状态并关闭:
void openFiles(ifstream& read, ofstream& write) { if (read.is_open()) { read.close(); } read.clear(); // 清除所有错误标志 read.open("StudentsPreformanceData.txt"); if (read.is_open()) cout << "File Opened" << endl; else cout << "Error try again"; if (!write.is_open()) { write.open("Results.txt"); write << fixed << showpoint << setprecision(2); } }
同时修正averageGrades中read.close()的位置:
double averageGrades(ifstream& read, double sum, int& count, char gender) { char student; double grade; count = 0; while (!read.eof()) { read >> student; read >> grade; if (student == gender) { count = count + 1; } cout << student << " " << count << " " << sum << endl; } read.close(); return count > 0 ? sum / count : 0; // 避免除以0 }
方案2:一次性读取数据(推荐)
一次性读取所有数据到容器,再遍历统计,避免多次IO操作:
#include<iostream> #include<iomanip> #include<fstream> #include<vector> using namespace std; struct Student { char gender; double gpa; }; void openFiles(ifstream& read, ofstream& write) { read.open("StudentsPreformanceData.txt"); if (!read.is_open()) { cout << "Error try again"; exit(1); } write.open("Results.txt"); write << fixed << showpoint << setprecision(2); } void loadStudents(ifstream& read, vector<Student>& students) { char gender; double gpa; while (read >> gender >> gpa) // 用读取操作作为循环条件,避免eof陷阱 { students.push_back({gender, gpa}); } read.close(); } void calculateStats(const vector<Student>& students, int& countF, double& sumF, int& countM, double& sumM) { countF = 0; sumF = 0.0; countM = 0; sumM = 0.0; for (const auto& s : students) { if (s.gender == 'f') { countF++; sumF += s.gpa; } else if (s.gender == 'm') { countM++; sumM += s.gpa; } } } void printResults(ofstream& write, int countF, double sumF, int countM, double sumM) { write << "Female Stats:" << endl; write << "Count: " << countF << endl; write << "Total GPA: " << sumF << endl; if (countF > 0) write << "Average GPA: " << sumF / countF << endl; write << "\nMale Stats:" << endl; write << "Count: " << countM << endl; write << "Total GPA: " << sumM << endl; if (countM > 0) write << "Average GPA: " << sumM / countM << endl; } int main() { ifstream read; ofstream write; openFiles(read, write); vector<Student> students; loadStudents(read, students); int countF, countM; double sumF, sumM; calculateStats(students, countF, sumF, countM, sumM); printResults(write, countF, sumF, countM, sumM); cout << "Female Count: " << countF << ", Total GPA: " << sumF << ", Average: " << (countF>0 ? sumF/countF : 0) << endl; cout << "Male Count: " << countM << ", Total GPA: " << sumM << ", Average: " << (countM>0 ? sumM/countM : 0) << endl; return 0; }
额外注意点
- 避免使用
while(!read.eof())作为循环条件,应直接用读取操作while(read >> student >> grade),避免最后一次读取异常。 - 统计平均值时需判断人数是否为0,防止除以0的错误。
内容的提问来源于stack exchange,提问作者Alexander Chapman
相关产品推荐
相关产品推荐

