文件I/O与异常处理
##实验任务一
contestant.hpp
#pragma once #include <iomanip> #include <iostream> #include <string> struct Contestant { long id; // 学号 std::string name; // 姓名 std::string major; // 专业 int solved; // 解题数 int penalty; // 总罚时 }; // 重载<< // 要求:姓名/专业里不含空白符 inline std::ostream& operator<<(std::ostream& out, const Contestant& c) { out << std::left; out << std::setw(15) << c.id << std::setw(15) << c.name << std::setw(15) << c.major << std::setw(10) << c.solved << std::setw(10) << c.penalty; return out; } // 重载>> inline std::istream& operator>>(std::istream& in, Contestant& c) { in >> c.id >> c.name >> c.major >> c.solved >> c.penalty; return in; }
utils.hpp
#pragma once #include <fstream> #include <iostream> #include <stdexcept> #include <string> #include <vector> #include "contestant.hpp" // ACM 排序规则:先按解题数降序,再按罚时升序 inline bool cmp_by_solve(const Contestant& a, const Contestant& b) { if(a.solved != b.solved) return a.solved > b.solved; return a.penalty < b.penalty; } // 将结果写至任意输出流 inline void write(std::ostream& os, const std::vector<Contestant>& v) { for (const auto& x : v) os << x << '\n'; } // 将结果打印到屏幕 inline void print(const std::vector<Contestant>& v) { write(std::cout, v); } // 将结果保存到文件 inline void save(const std::string& filename, const std::vector<Contestant>& v) { std::ofstream os(filename); if (!os) throw std::runtime_error("fail to open " + filename); write(os, v); } // 从文件读取信息(跳过标题行) inline std::vector<Contestant> load(const std::string& filename) { std::ifstream is(filename); if (!is) throw std::runtime_error("fail to open " + filename); std::string line; std::getline(is, line); // 跳过标题 std::vector<Contestant> v; Contestant t; int seq; while (is >> seq >> t) v.push_back(t); return v; }
task1.cpp
#include <algorithm> #include <iostream> #include <stdexcept> #include <vector> #include "contestant.hpp" #include "utils.hpp" const std::string in_file = "./data.txt"; const std::string out_file = "./ans.txt"; void app() { std::vector<Contestant> contestants; try { contestants = load(in_file); std::sort(contestants.begin(), contestants.end(), cmp_by_solve); print(contestants); save(out_file, contestants); } catch (const std::exception& e) { std::cerr << e.what() << '\n'; return; } } int main() { app(); }

问题一:(1) std::cout的类型是 std::ostream的成员函数,std::cout能从 std::ostream中继承数据流。
(2)不需要改动。
问题二:在utils.hpp的
throw std::runtime_error("fail to open " + filename);与
throw std::runtime_error("fail to open " + filename);都会在文件打开失败是抛出异常。
(2)异常会被task1.cpp的

实验二
student.hpp
#pragma once #include <iostream> #include <string> class Student { public: Student() = default; ~Student() = default; const std::string get_major() const; int get_grade() const; friend std::ostream& operator<<(std::ostream& os, const Student& s); friend std::istream& operator>>(std::istream& is, Student& s); private: int id; std::string name; std::string major; int grade; // 0-100 };
stumgr.hpp
#pragma once #include <string> #include <vector> #include "student.hpp" class StuMgr { public: void load(const std::string& file); // 加载数据文件(空格分隔) void sort(); // 排序: 按专业字典序升序、同专业分数降序 void print() const; // 打印到屏幕 void save(const std::string& file) const; // 保存到文件 private: void write(std::ostream &os) const; // 把数据写到任意输出流 private: std::vector<Student> students; };
task2.cpp
#include <iostream> #include <limits> #include <string> #include "stumgr.hpp" const std::string in_file = "./data.txt"; const std::string out_file = "./ans.txt"; void menu() { std::cout << "\n**********简易应用**********\n" "1. 加载文件\n" "2. 排序\n" "3. 打印到屏幕\n" "4. 保存到文件\n" "5. 退出\n" "请选择:"; } void app() { StuMgr mgr; while(true) { menu(); int choice; std::cin >> choice; try { switch (choice) { case 1: mgr.load(in_file); std::cout << "加载成功\n"; break; case 2: mgr.sort(); std::cout << "排序已完成\n"; break; case 3: mgr.print(); std::cout << "打印已完成\n"; break; case 4: mgr.save(out_file); std::cout << "导出成功\n"; break; case 5: return; default: std::cout << "不合法输入\n"; } } catch (const std::exception& e) { std::cout << "Error: " << e.what() << '\n'; } } } int main() { app(); }
student.cpp
#include "student.hpp" #include <limits> #include <iomanip> // 构造函数 Student::Student(int id, const std::string& name, const std::string& major, int score) : id(id), name(name), major(major), score(score) {} // Getter方法实现 int Student::getId() const { return id; } const std::string& Student::getName() const { return name; } const std::string& Student::getMajor() const { return major; } int Student::getScore() const { return score; } // Setter方法实现 void Student::setId(int newId) { id = newId; } void Student::setName(const std::string& newName) { name = newName; } void Student::setMajor(const std::string& newMajor) { major = newMajor; } void Student::setScore(int newScore) { score = newScore; } // 重载小于运算符:按专业字典序,专业内按成绩降序 bool Student::operator<(const Student& other) const { if (major != other.major) { return major < other.major; } return score > other.score; // 降序排列 } // 重载输入运算符 std::istream& operator>>(std::istream& is, Student& student) { is >> student.id; is.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); std::getline(is, student.name); std::getline(is, student.major); is >> student.score; return is; } // 重载输出运算符 std::ostream& operator<<(std::ostream& os, const Student& student) { os << std::setw(6) << student.id << " " << std::setw(10) << std::left << student.name << " " << std::setw(10) << std::left << student.major << " " << std::setw(5) << student.score; return os; }
#include "stumgr.hpp" #include <fstream> #include <algorithm> #include <iomanip> #include <stdexcept> #include <numeric> #include <map> // 异常类实现 FileOpenException::FileOpenException(const std::string& filename, const std::string& mode) : std::runtime_error("无法打开文件: " + filename + " (模式: " + mode + ")") {} // 构造函数 Stumgr::Stumgr() : dataLoaded(false) {} // 从文件加载数据 void Stumgr::loadFromFile(const std::string& filename) { std::ifstream inFile; inFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); try { inFile.open(filename); // 读取数据头(如果存在) std::string header; std::getline(inFile, header); students.clear(); Student student; while (inFile >> student) { students.push_back(student); } currentFile = filename; dataLoaded = true; } catch (const std::ifstream::failure& e) { throw FileOpenException(filename, "读取"); } } // 保存数据到文件 void Stumgr::saveToFile(const std::string& filename) { std::string saveFile = filename.empty() ? currentFile : filename; std::ofstream outFile; outFile.exceptions(std::ofstream::failbit | std::ofstream::badbit); try { outFile.open(saveFile); // 写入数据头 outFile << "ID 姓名 专业 成绩" << std::endl; for (const auto& student : students) { outFile << student.getId() << std::endl << student.getName() << std::endl << student.getMajor() << std::endl << student.getScore() << std::endl; } std::cout << "数据已保存到 " << saveFile << std::endl; } catch (const std::ofstream::failure& e) { throw FileOpenException(saveFile, "写入"); } } // 排序数据:按专业字典序,专业内按成绩降序 void Stumgr::sortData() { if (!dataLoaded) { std::cout << "请先加载数据!" << std::endl; return; } std::sort(students.begin(), students.end()); std::cout << "数据已排序完成!" << std::endl; } // 显示所有学生信息 void Stumgr::displayAll() const { if (!dataLoaded) { std::cout << "请先加载数据!" << std::endl; return; } std::cout << std::setw(6) << "学号" << " " << std::setw(10) << std::left << "姓名" << " " << std::setw(10) << std::left << "专业" << " " << std::setw(5) << "成绩" << std::endl; std::cout << std::string(40, '-') << std::endl; for (const auto& student : students) { std::cout << student << std::endl; } } // 按专业显示学生信息 void Stumgr::displayByMajor(const std::string& major) const { if (!dataLoaded) { std::cout << "请先加载数据!" << std::endl; return; } std::cout << "专业: " << major << std::endl; std::cout << std::setw(6) << "学号" << " " << std::setw(10) << std::left << "姓名" << " " << std::setw(5) << "成绩" << std::endl; std::cout << std::string(30, '-') << std::endl; for (const auto& student : students) { if (student.getMajor() == major) { std::cout << std::setw(6) << student.getId() << " " << std::setw(10) << std::left << student.getName() << " " << std::setw(5) << student.getScore() << std::endl; } } } // 显示统计信息 void Stumgr::displayStatistics() const { if (!dataLoaded) { std::cout << "请先加载数据!" << std::endl; return; } std::cout << "\n===== 统计信息 =====" << std::endl; std::cout << "总人数: " << students.size() << std::endl; std::cout << "平均分: " << std::fixed << std::setprecision(1) << getAverageScore() << std::endl; Student highest = getHighestScore(); Student lowest = getLowestScore(); std::cout << "最高分: " << highest.getName() << " (" << highest.getScore() << "分)" << std::endl; std::cout << "最低分: " << lowest.getName() << " (" << lowest.getScore() << "分)" << std::endl; // 按专业统计 std::map<std::string, int> majorCount; for (const auto& student : students) { majorCount[student.getMajor()]++; } std::cout << "\n各专业人数:" << std::endl; for (const auto& pair : majorCount) { std::cout << " " << pair.first << ": " << pair.second << "人" << std::endl; } } // 计算平均分 double Stumgr::getAverageScore() const { if (students.empty()) return 0.0; int total = 0; for (const auto& student : students) { total += student.getScore(); } return static_cast<double>(total) / students.size(); } // 获取最高分学生 Student Stumgr::getHighestScore() const { if (students.empty()) { return Student(); } auto it = std::max_element(students.begin(), students.end(), [](const Student& a, const Student& b) { return a.getScore() < b.getScore(); }); return *it; } // 获取最低分学生 Student Stumgr::getLowestScore() const { if (students.empty()) { return Student(); } auto it = std::min_element(students.begin(), students.end(), [](const Student& a, const Student& b) { return a.getScore() < b.getScore(); }); return *it; }



text:


浙公网安备 33010602011771号