用 C++ 实现的单机版图书管理系统,具备完整借还管理、库存统计、热度排行、数据持久化和命令行交互界面。
1. 程序实现的功能清单:
| 编号 | 功能 | 说明 |
|---|---|---|
| 1 | 添加图书 | ISBN/书名/作者/类型/库存 |
| 2 | 修改图书 | 支持改 ISBN(级联更新读者记录) |
| 3 | 入库 | 采购新书,库存增加 |
| 4 | 下架 | 报废/淘汰,库存减少 |
| 5 | 图书列表 | 显示所有图书及借出情况 |
| 6 | 统计 | 种类/总藏量/可借/已借出 |
| 7 | 读者注册 | ID/姓名/最大借阅数 |
| 8 | 修改读者 | ID/姓名/借阅上限 |
| 9 | 借书 | 库存校验、上限校验、重复校验 |
| 10 | 还书 | 自动记录归还时间 |
| 11 | 读者列表 | 借阅记录详情 |
| 12 | 热度排行 | 降序/升序,辅助采购&下架决策 |
| 13 | 保存数据 | 手动保存到文件 |
| 14 | 加载数据 | 从文件恢复 |
| 15 | 借阅记录查询 | 按 ISBN 查所有借阅历史 |
| 输入校验 | 类型检查 + y/n 确认机制 | |
| 启动自动加载 | 程序启动读取文件 | |
| 0 | 退出询问保存 | 防止数据丢失 |
2. 设计框架
分层架构:
数据关系:
命令行交互,程序运行示例图:
交互界面,选择 “保存数据” 后-->
读者信息,保存在 readers.txt 文件中
图书数据库信息,保存在 books.txt 文件中
BookHub.cpp 代码
#include "pch.h" #define BOOKFILE "books.txt" #define READERFILE "readers.txt" // 借阅记录 struct BorrowRecord { std::string Isbn; // 借阅的图书 ISBN std::string BorrowTime; // 借阅时间 std::string ReturnTime; // 归还时间(空字符串表示未归还) // 借阅记录 BorrowRecord(const std::string& bookIsbn, const std::string& borrowTime) : Isbn(bookIsbn),BorrowTime(borrowTime),ReturnTime("") {} // 是否已归还 bool IsReturned() const{ return !ReturnTime.empty(); } }; // 获取当前时间, 转换为字符串 inline std::string GetCurrentTimeStr() { auto now = std::time(nullptr); // 获取当前秒数 auto* tm = std::localtime(&now);// 秒数 → 年月日时分秒 std::ostringstream oss; oss << std::put_time(tm,"%Y-%m-%d %H:%M:%S"); return oss.str(); } class Book { protected: std::string m_BookIsbn; // 图书唯一标识码, 例如 "978-7-115-49250-0" std::string m_BookName; // 书名 std::string m_BookAuthor; // 作者 std::string m_BookType; // 类型 u_int32_t m_stock; // 单本书:当前可借数量 ( 剩余库存 ) u_int32_t m_total; // 单本书:总藏书量(包括已借出的) public: Book(const std::string& isbn,const std::string& name,const std::string& author \ ,const std::string& type,u_int32_t stock,u_int32_t total = 0) : m_BookIsbn(isbn),m_BookName(name),m_BookAuthor(author),\ m_BookType(type), m_stock(stock), m_total(total == 0 ? stock : total) {} const std::string& GetBookIsbn() const {return m_BookIsbn;} const std::string& GetBookName() const {return m_BookName;} const std::string& GetBookAuthor() const {return m_BookAuthor;} const std::string& GetBookType() const {return m_BookType;} u_int32_t Get_stock() const {return m_stock;} u_int32_t Get_total() const {return m_total;} // 当录入错误信息时,修改信息 void ResetBookIsbn(const std::string& isbn) { m_BookIsbn = isbn; } void ResetBookName(const std::string& name) { m_BookName = name; } void ResetBookAuthor(const std::string& author) { m_BookAuthor = author; } void ResetBookType(const std::string& type) { m_BookType = type; } // 单本书:增加库存(采购新书) void AddStock(uint32_t count) { m_stock += count; m_total += count; std::cout << "书名:" << m_BookName << " 入库:" << count << " 本,当前库存:" << m_stock << "/" << m_total << std::endl; } // 单本书 下架:淘汰/报废 bool RemoveStock(uint32_t count) { if(count > m_stock) { std::cout << "下架失败:可下架数量不能超过当前库存 -> " << m_stock << std::endl; return false; } m_stock -= count; m_total -= count; std::cout << "书名:" << m_BookName << " 下架:" << count << " 本,当前库存:" << m_stock << "/" << m_total <<std::endl; return true; } // 单本书:可借数量 uint32_t GetAvailable() const { return m_stock; } // 单本书:已借出数量 uint32_t GetBorrowedCount() const { return m_total - m_stock; } // 图书信息 void PrintBookInfo() const { std::cout << "书名:" << m_BookName << " 作者:" << m_BookAuthor << " 类型:" << m_BookType << " 可借:" << m_stock << " 本," << " 已借:" << GetBorrowedCount() << " 本," << " 总计:" << m_total << " 本" << std::endl; } // 借书 库存减 bool BorrowOne() { if(m_stock > 0){ m_stock--; return true; } return false; } // 还书 库存加 void ReturnOne() { if(m_stock < m_total) m_stock++; } // 序列化为文件格式 std::string Serialize() const { return m_BookIsbn + "|" + m_BookName + "|" + m_BookAuthor + "|" + m_BookType + "|" + std::to_string(m_stock) + "|" + std::to_string(m_total); } // 从文件格式反序列化 static Book Deserialize(const std::string& line) { std::stringstream ss(line); std::string isbn, name, author, type, stockStr, totalStr; std::getline(ss, isbn, '|'); std::getline(ss, name, '|'); std::getline(ss, author, '|'); std::getline(ss, type, '|'); std::getline(ss, stockStr, '|'); std::getline(ss, totalStr, '|'); Book book(isbn, name, author, type, \ std::stoul(stockStr), std::stoul(totalStr)); return book; } virtual ~Book() = default; }; class Reader { private: uint32_t m_Id; // 读者ID std::string m_Name; // 姓名 std::string m_CreateTime; // 读者创建时间 std::vector<BorrowRecord> m_BorrowRecords; // 借阅记录列表 int m_MaxLimit; // 最大借阅数量 public: Reader(uint32_t id,const std::string& name,int limit) : m_Id(id),m_Name(name),m_CreateTime(GetCurrentTimeStr()),m_MaxLimit(limit) {} uint32_t GetId() const { return m_Id; } const std::string& GetName() const { return m_Name; } const std::string& GetCreateTime() const { return m_CreateTime; } int GetMaxLimit() const { return m_MaxLimit; } // 修改读者信息 void ResetReaderId(uint32_t id){ m_Id = id; } void ResetReaderName(std::string name){ m_Name = name; } void ResetReaderMaxLimit(int limit){ m_MaxLimit = limit; } void UpdateBorrowRecordISBN(const std::string& oldIsbn, const std::string& newIsbn) { for(auto& record : m_BorrowRecords){ if(record.Isbn == oldIsbn) record.Isbn = newIsbn; } } // 当前 已经借了几本书 int GetCurrentBorrowCount() const{ int count = 0; for(const auto& record : m_BorrowRecords){ if(record.ReturnTime.empty()){ count++; } } return count; } // 历史 总借阅次数 int GetTotalBorrowCount() const{ return m_BorrowRecords.size(); } // 是否达到 可借阅上限 bool CanBorrow() const { return GetCurrentBorrowCount() < m_MaxLimit; } // 检查是否已借过某书(且未归还) bool HasBook(const std::string& isbn) const { for(const auto& record : m_BorrowRecords){ if(record.Isbn == isbn && record.ReturnTime.empty()){ return true; } } return false; } // 借书 bool BorrowBook(const std::string& isbn){ if(!CanBorrow()){ std::cout << "借阅失败:已达到最大借阅数量 " << m_MaxLimit << std::endl; return false; } if(HasBook(isbn)){ std::cout << "借阅失败:已借过此书且未归还" << std::endl; return false; } m_BorrowRecords.emplace_back(isbn,GetCurrentTimeStr()); std::cout << m_Name << " 成功借阅 ISBN:" << isbn << ",时间:" << m_BorrowRecords.back().BorrowTime << std::endl; return true; } // 还书 bool ReturnBook(const std::string& isbn){ for(auto& record : m_BorrowRecords){ if(record.Isbn == isbn && record.ReturnTime.empty()){ record.ReturnTime = GetCurrentTimeStr(); std::cout << m_Name << " 成功归还 ISBN: " << isbn << ",时间: " << record.ReturnTime << std::endl; return true; } } // 借阅时系统做没有记录,或者归还的不是此读者的书 std::cout << "归还失败:未找到该书的借阅记录" << std::endl; return false; } // 获取当前借阅的 ISBN 列表 std::vector<std::string> GetCurrentBorrowedISBNs() const{ std::vector<std::string> isbns; for(const auto& record : m_BorrowRecords){ if(record.ReturnTime.empty()){ isbns.emplace_back(record.Isbn); } } return isbns; } // 获取所有借阅记录 const std::vector<BorrowRecord>& GetBorrowRecords() const { return m_BorrowRecords; } // 打印读者的注册信息 void PrintReaderInfo(){ std::cout << "ID:" << m_Id << " Name:" << m_Name << " 注册时间:" << m_CreateTime << std::endl; } // 打印读者信息 void PrintInfo() const { std::cout << "ID:" << m_Id << " Name:" << m_Name << " 注册时间:" << m_CreateTime << " 当前借阅:" << GetCurrentBorrowCount() << "/" << m_MaxLimit << " 本" << std::endl; if(!m_BorrowRecords.empty()){ std::cout << "借阅记录: " << std::endl; for(const auto& record : m_BorrowRecords){ std::cout << "ISBN:" << record.Isbn << " 借阅时间:" << record.BorrowTime; if(record.ReturnTime.empty()){ std::cout << " 未归还" << std::endl; }else{ std::cout << " 归还时间:" << record.ReturnTime << std::endl; } } } } // 序列化读者信息 std::string SerializeInfo() const { return "R:" + std::to_string(m_Id) + "|" + m_Name + "|" + m_CreateTime + "|" + std::to_string(m_MaxLimit); } // 序列化借阅记录 std::vector<std::string> SerializeRecords() const { std::vector<std::string> lines; for(const auto& record : m_BorrowRecords){ lines.push_back("B:" + std::to_string(m_Id) + "|" + record.Isbn + "|" + record.BorrowTime + "|" + record.ReturnTime); } return lines; } // 从文件格式反序列化读者信息 static Reader DeserializeInfo(const std::string& line) { std::stringstream ss(line.substr(2)); // 跳过 "R:" std::string idStr, name, createTime, limitStr; std::getline(ss, idStr, '|'); std::getline(ss, name, '|'); std::getline(ss, createTime, '|'); std::getline(ss, limitStr, '|'); Reader reader(std::stoul(idStr), name, std::stoi(limitStr)); // 恢复注册时间 reader.m_CreateTime = createTime; return reader; } // 添加借阅记录(从文件恢复时用) void AddBorrowRecord(const BorrowRecord& record) { m_BorrowRecords.push_back(record); } }; class LibraryManager { private: // 按键排序的映射表, 红黑树(平衡二叉搜索树),分配在堆上 std::map<std::string, Book> m_Books; // ISBN -> Book std::map<int,Reader> m_Readers; // ReaderID -> Reader public: /* 图书管理 */ // 核心方法:接收 Book 对象 bool AddBook(const Book& book){ if(m_Books.find(book.GetBookIsbn()) != m_Books.end()){ std::cout << "图书:" << book.GetBookIsbn() << " 已存在!" << std::endl; return false; } m_Books.emplace(book.GetBookIsbn(),book); std::cout << "成功添加 图书:" << book.GetBookName() << std::endl; return true; } // 便捷添加方法,只传必要参数 (委托给核心方法) bool AddBook(const std::string& isbn, const std::string& name, const std::string& author, const std::string& type, uint32_t stock) { return AddBook(Book(isbn, name, author, type, stock)); } // 初始化列表批量添加 void AddBooks(std::initializer_list<Book> books){ for(const auto& book : books){ AddBook(book); // 逐个调用单本添加方法 } } // 图书列表 void ShowAllBooks() const { for(const auto& [isbn,book] : m_Books){ std::cout << "书名:" << book.GetBookName() << " 作者:" << book.GetBookAuthor() << " 类型:" << book.GetBookType() << " 可借:" << book.Get_stock() << " 借出:" << book.GetBorrowedCount() << " ISBN:" << isbn << std::endl; } } Book* FindBook(const std::string& isbn) { auto it = m_Books.find(isbn); return it != m_Books.end() ? &it->second : nullptr; } // 入库 bool AddBookStock(const std::string& isbn, uint32_t count) { auto* book = FindBook(isbn); if(!book) { std::cout << "该图书不存在!" << std::endl; return false; } book->AddStock(count); return true; } // 下架 bool RemoveBookStock(const std::string& isbn, uint32_t count) { auto* book = FindBook(isbn); if(!book) { std::cout << "该图书不存在!" << std::endl; return false; } return book->RemoveStock(count); } // 修改图书信息 bool ResetBookInfo(const std::string& oldIsbn, const std::string& newIsbn, const std::string& name, const std::string& author, const std::string& type) { auto it = m_Books.find(oldIsbn); if (it == m_Books.end()) { std::cout << "该图书不存在!" << std::endl; return false; } std::string finalIsbn = newIsbn.empty() ? oldIsbn : newIsbn; // 如果 ISBN 变了,检查新 ISBN 是否已存在 if(finalIsbn != oldIsbn && m_Books.find(finalIsbn) != m_Books.end()){ std::cout << "新 ISBN 已在数据库中!" << std::endl; return false; } Book book = it->second; book.ResetBookIsbn(finalIsbn); // 非空才更新 if (!name.empty()) book.ResetBookName(name); if (!author.empty()) book.ResetBookAuthor(author); if (!type.empty()) book.ResetBookType(type); m_Books.erase(it); m_Books.emplace(finalIsbn,book); // 同步更新所有读者 借阅记录里的isbn,避免还书失败 if(finalIsbn != oldIsbn){ for(auto& [id,reader] : m_Readers){ reader.UpdateBorrowRecordISBN(oldIsbn,finalIsbn); } } return true; } // 图书馆统计 void ShowStatistics() const { uint32_t stock = 0; uint32_t total = 0; for(const auto& [isbn,book] : m_Books){ stock += book.Get_stock(); total += book.Get_total(); } std::cout << "===== 图书馆统计 =====" << std::endl; std::cout << "图书种类: " << m_Books.size() << std::endl; std::cout << "总藏书量: " << total << " 本" << std::endl; std::cout << "可借数量: " << stock << " 本" << std::endl; std::cout << "已借出: " << total- stock << " 本" << std::endl; } // 图书 热度排行榜 ( 参考此数据:热门图书增加库存,冷门图书可做下架处理,避免占用库存和资金 ) // value == true 降序排列, value == false 升序排列 void ShowBookRanking(bool value = true) const { struct RankItem { std::string isbn; std::string name; uint32_t borrowed; // 借出数量 uint32_t stock; // 剩余库存 uint32_t total; // 总藏书量 }; std::vector<RankItem> ranking; for(const auto& [isbn,book] : m_Books){ ranking.push_back({isbn, book.GetBookName(), book.GetBorrowedCount(), book.Get_stock(), book.Get_total()}); } if (ranking.empty()) { std::cout << "没有库存信息" << std::endl; return; } if(value){ // 按借出数量 降序排列 std::sort(ranking.begin(), ranking.end(), [](const RankItem& a,const RankItem& b) { return a.borrowed > b.borrowed; } ); } else { // 按借出数量 升序排列 std::sort(ranking.begin(), ranking.end(), [](const RankItem& a,const RankItem& b) { return a.borrowed < b.borrowed; } ); } // 输出 std::cout << "\n===== 图书热度排行 =====" << std::endl; uint32_t count = 1; for(const auto& item : ranking){ std::cout << count++ << " 借出:" << item.borrowed << " 书名:" << item.name << " 库存:" << item.stock << "/" << item.total << " ISBN:" << item.isbn << std::endl; } } // 图书 按类型排行 void ShowBookType(const std::string& type) const { struct RankItem { std::string isbn; std::string name; uint32_t borrowed; // 借出数量 uint32_t stock; // 剩余库存 uint32_t total; // 总藏书量 }; std::vector<RankItem> ranking; for(const auto& [isbn,book] : m_Books){ if(book.GetBookType() == type) { ranking.push_back({isbn, book.GetBookName(), book.GetBorrowedCount(), book.Get_stock(), book.Get_total()}); } } if (ranking.empty()) { std::cout << "该类型没有库存信息" << std::endl; return; } // 按借出数量 降序排列 std::sort(ranking.begin(), ranking.end(), [](const RankItem& a,const RankItem& b) { return a.borrowed > b.borrowed; } ); // 输出 std::cout << "\n===== 图书热度排行 =====" << std::endl; std::cout << type << std::endl; uint32_t count = 1; for(const auto& item : ranking){ std::cout << count++ << " 借出:" << item.borrowed << " 书名:" << item.name << " 库存:" << item.stock << "/" << item.total << " ISBN:" << item.isbn << std::endl; } } // 读者管理 bool AddReader(const Reader& reader) { if(m_Readers.find(reader.GetId()) != m_Readers.end()){ std::cout << "读者ID " << reader.GetId() << " 已存在!" << std::endl; return false; } m_Readers.emplace(reader.GetId(),reader); std::cout << "读者 " << reader.GetName() << " 注册成功, ID: " << reader.GetId() << std::endl; return true; } // 已注册读者列表 void ShowAllReaders() const { for(const auto& [id,reader] : m_Readers){ reader.PrintInfo(); std::cout << std::endl; } } // 修改读者信息 bool ResetReaderInfo(uint32_t oldId, uint32_t newId, const std::string& name,int limit) { auto it = m_Readers.find(oldId); if (it == m_Readers.end()) return false; uint32_t finalId = (newId != 0) ? newId : oldId; // 没改就用旧的 // 如果 ID 变了,检查新 ID 是否已存在 if (finalId != oldId && m_Readers.find(finalId) != m_Readers.end()) { std::cout << "新 ID 已存在!" << std::endl; return false; } Reader reader = it->second; reader.ResetReaderId(finalId); if (!name.empty()) reader.ResetReaderName(name); if (limit) reader.ResetReaderMaxLimit(limit); m_Readers.erase(it); m_Readers.emplace(finalId, reader); return true; } Reader* FindReader(uint32_t id){ auto it = m_Readers.find(id); return it != m_Readers.end() ? &it->second : nullptr; } // 借书 bool BorrowBook(int readerId,const std::string& isbn) { auto* reader = FindReader(readerId); auto* book = FindBook(isbn); if(!reader) { std::cout << "借阅失败:读者未注册!" << std::endl; return false; } if(!book) { std::cout << "借阅失败:数据库没有此书!" << std::endl; return false; } if(!book->BorrowOne()) { std::cout << "借阅失败:库存不足!" << std::endl; return false; } if(!reader->BorrowBook(isbn)) { book->ReturnOne(); // 读者不能借阅此书,回滚库存 return false; } return true; // 成功借阅 } // 还书 bool ReturnBook(int readerId,const std::string& isbn) { auto* reader = FindReader(readerId); auto* book = FindBook(isbn); if(!reader) { std::cout << "归还失败:读者未注册!" << std::endl; return false; } if(!book) { std::cout << "归还失败:数据库没有此书!" << std::endl; return false; } if (!reader->ReturnBook(isbn)) { return false; } book->ReturnOne(); return true; } // 按 ISBN 查询借阅记录 void ShowBookBorrowHistory(const std::string& isbn) { auto* book = FindBook(isbn); if(!book) { std::cout << "数据库中 没有此书!" << std::endl; return; } std::cout << "书名:" << book->GetBookName() << " 借阅记录:\n"; std::cout << "当前库存:" << book->Get_stock() << "/" << book->Get_total() << std::endl; bool found = false; for(const auto& [id,reader] : m_Readers) { for(const auto& record : reader.GetBorrowRecords()) { if(record.Isbn == isbn) { found = true; std::cout << "ID:" << id << " 读者:" << reader.GetName() << " 借阅时间:" << record.BorrowTime; if(record.ReturnTime.empty()) { std::cout << " 未归还" << std::endl; } else { std::cout << " 归还时间:" << record.ReturnTime << std::endl; } } } } if(!found) { std::cout << "暂无借阅记录" << std::endl; } } // 数据持久化 ( 存入文件 ) bool SaveToFile(const std::string& booksFile = BOOKFILE, const std::string& readersFile = READERFILE) { // 保存图书 std::ofstream bf(booksFile); if(!bf){ std::cout << "无法打开 " << booksFile << std::endl; return false; } for(const auto& [isbn,book] : m_Books){ bf << book.Serialize() << std::endl; } bf.close(); // 保存读者和借阅记录 std::ofstream rf(readersFile); if(!rf){ std::cout << "无法打开 " << readersFile << std::endl; return false; } for(const auto& [id,reader] : m_Readers){ rf << reader.SerializeInfo() << std::endl; auto records = reader.SerializeRecords(); for(const auto& rec : records){ rf << rec << std::endl; // 所有借阅记录 } rf << std::endl; // 空行分隔不同读者的信息 } rf.close(); std::cout << "数据已保存!" << std::endl; return true; } bool LoadFromFile(const std::string& booksFile = BOOKFILE, const std::string& readersFile = READERFILE) { // 清空现有数据 m_Books.clear(); m_Readers.clear(); // 加载图书 std::ifstream bf(booksFile); if(!bf) { std::cout << "未找到 " << booksFile << std::endl; }else { std::string line; while(std::getline(bf, line)){ if(line.empty()) continue; try { Book book = Book::Deserialize(line); m_Books.emplace(book.GetBookIsbn(),book); } catch(...) { std::cout << "跳过损坏的图书数据: " << line << std::endl; } } bf.close(); } // 加载读者和借阅记录 std::ifstream rf(readersFile); if (!rf) { std::cout << "未找到 " << readersFile << std::endl; } else { std::string line; Reader* currentReader = nullptr; while(std::getline(rf,line)) { if(line.empty()){ currentReader = nullptr; continue; } if(line[0] == 'R' && line[1] == ':'){ try { // 解析 读者注册信息 Reader reader = Reader::DeserializeInfo(line); auto [it,ok] = m_Readers.emplace(reader.GetId(),reader); if(ok) { currentReader = &it->second; } } catch(...) { std::cout << "跳过损坏的读者数据: " << line << std::endl; currentReader = nullptr; } } else if (line[0] == 'B' && line[1] == ':' && currentReader) { try { // 解析 借阅记录 std::stringstream ss(line.substr(2)); // 跳过 "B:" std::string idStr, isbn, borrowTime, returnTime; std::getline(ss, idStr, '|'); std::getline(ss, isbn, '|'); std::getline(ss, borrowTime, '|'); std::getline(ss, returnTime, '|'); BorrowRecord record(isbn, borrowTime); record.ReturnTime = returnTime; currentReader->AddBorrowRecord(record); } catch(...) { std::cout << "跳过损坏的借阅记录: " << line << std::endl; } } } rf.close(); } std::cout << "数据加载完成!" << std::endl; ShowStatistics(); return true; } }; std::string SafeInputString(const std::string& prompt) { std::string line; std::cout << prompt; std::getline(std::cin, line); return line; } // 带确认的字符串输入 std::string SafeInputStringConfirm(const std::string& prompt) { while (true) { std::string line = SafeInputString(prompt); std::cout << "输入: \"" << line << "\" 确认? (y/n): "; std::string confirm; std::getline(std::cin, confirm); if (confirm == "y" || confirm == "Y" || confirm.empty()) { return line; } std::cout << "请重新输入" << std::endl; } } uint32_t SafeInputNum(const std::string& prompt) { while(true){ std::cout << prompt; std::string line; std::getline(std::cin, line); try{ unsigned long value = std::stoul(line); // string → unsigned long return static_cast<uint32_t>(value); // unsigned long → uint32_t } catch(...){ // 如果转换失败了,跳到这里执行 std::cout << "输入无效,请输入整数!" << std::endl; } } } // 带确认的数字输入 uint32_t SafeInputNumConfirm(const std::string& prompt) { while (true) { uint32_t value = SafeInputNum(prompt); std::cout << "输入: " << value << " 确认? (y/n): "; std::string confirm; std::getline(std::cin, confirm); if (confirm == "y" || confirm == "Y" || confirm.empty()) { return value; } std::cout << "请重新输入" << std::endl; } } void CmdlineAddBook(LibraryManager& lib) { std::string isbn = SafeInputStringConfirm("ISBN:"); if (lib.FindBook(isbn)) { std::cout << "该 ISBN 已存在!" << std::endl; return; } std::string name = SafeInputStringConfirm("书名:"); std::string author = SafeInputStringConfirm("作者:"); std::string type = SafeInputStringConfirm("类型:"); uint32_t stock = SafeInputNumConfirm("库存:"); lib.AddBook(isbn, name, author, type, stock); } void CmdlineAddBookStock(LibraryManager& lib) { std::string isbn = SafeInputStringConfirm("ISBN:"); uint32_t count = SafeInputNumConfirm("数量:"); lib.AddBookStock(isbn,count); } void CmdlineRemoveBookStock(LibraryManager& lib) { std::string isbn = SafeInputStringConfirm("ISBN:"); uint32_t count = SafeInputNumConfirm("数量:"); lib.RemoveBookStock(isbn,count); } void CmdlineResetBookInfo(LibraryManager& lib) { std::string oldIsbn = SafeInputStringConfirm("ISBN:"); Book* book = lib.FindBook(oldIsbn); if(!book) { std::cout << "数据库没有此书!" << std::endl; return; } book->PrintBookInfo(); std::cout << std::endl; std::cout << "( 回车保留原值,输入新值覆盖 )" << std::endl; std::string newIsbn = SafeInputStringConfirm("set ISBN:"); std::string name = SafeInputStringConfirm("set 书名:"); std::string author = SafeInputStringConfirm("set 作者:"); std::string type = SafeInputStringConfirm("set 类型:"); lib.ResetBookInfo(oldIsbn, newIsbn, name, author, type); std::cout << "图书信息 修改完成" << std::endl; } void CmdlineAddReader(LibraryManager& lib) { uint32_t id = SafeInputNumConfirm("读者ID:"); if (lib.FindReader(id)) { std::cout << "该 ID 已存在!" << std::endl; return; } std::string name = SafeInputStringConfirm("姓名:"); int limit = SafeInputNumConfirm("最大借阅数:"); lib.AddReader(Reader(id, name, limit)); } void CmdlineResetReaderInfo(LibraryManager& lib) { uint32_t oldId= SafeInputNumConfirm("读者ID:"); Reader* reader = lib.FindReader(oldId); if(!reader) { std::cout << "读者未注册!" << std::endl; return; } reader->PrintReaderInfo(); std::cout << std::endl; std::cout << "( 回车保留原值,输入新值覆盖 )" << std::endl; uint32_t newId = SafeInputNumConfirm("set ID:"); std::string name = SafeInputStringConfirm("set 姓名:"); int limit = SafeInputNumConfirm("set 最大借阅数:"); lib.ResetReaderInfo(oldId, newId, name, limit); std::cout << "读者信息 修改完成" << std::endl; } void CmdlineBorrowBook(LibraryManager& lib) { int readerId = SafeInputNumConfirm("读者ID:"); std::string isbn = SafeInputStringConfirm("ISBN:"); lib.BorrowBook(readerId,isbn); } void CmdlineReturnBook(LibraryManager& lib) { int readerId = SafeInputNumConfirm("读者ID:"); std::string isbn = SafeInputStringConfirm("ISBN:"); lib.ReturnBook(readerId,isbn); } void CmdlineShowBookRanking(LibraryManager& lib) { std::string choice = SafeInputStringConfirm("降序:y 升序:n "); lib.ShowBookRanking(choice != "n"); } void CmdlineShowBookType(LibraryManager& lib) { std::string type = SafeInputStringConfirm("图书类型:"); lib.ShowBookType(type); } void CmdlineShowBookHistory(LibraryManager& lib) { std::string isbn = SafeInputStringConfirm("ISBN:"); lib.ShowBookBorrowHistory(isbn); } void CmdlineSave(LibraryManager& lib) { lib.SaveToFile(); } void CmdlineLoad(LibraryManager& lib) { std::string confirm = SafeInputStringConfirm("加载数据,会清空当前未保存的数据,确认加载? (y/n): "); if (confirm == "y" || confirm == "Y") { lib.LoadFromFile(); } else { std::cout << "已取消加载操作" << std::endl; } } volatile sig_atomic_t stop = 0; void handle_sigint(int sig) { stop = 1; } int main(int argc,char* argv[]) { #if 1 // 命令行 交互输入 LibraryManager lib; lib.LoadFromFile(); // 启动时自动加载 图书信息/读者信息/借阅信息 /* 捕获 Ctrl+C 信号 */ signal(SIGINT, handle_sigint); signal(SIGTERM, handle_sigint); int choice; while(!stop){ std::cout << std::endl; std::cout << "================ 图书管理系统 ================" << std::endl; std::cout << "1.添加图书 2.修改图书 3.入库 4.下架 5.图书列表 6.统计" << std::endl; std::cout << "7.读者注册 8.修改读者 9.借书 10.还书 11.读者列表 12.图书排行榜" << std::endl; std::cout << "13.分类排行 14.保存数据 15.加载数据 16.图书借阅记录 0.退出" << std::endl; choice = SafeInputNum("请选择: "); switch(choice) { case 0: { std::string saveChoice = SafeInputStringConfirm("退出前保存数据? (y/n): "); if (saveChoice == "y" || saveChoice == "Y") { lib.SaveToFile(); } stop = 1; break; } case 1: CmdlineAddBook(lib); break; case 2: CmdlineResetBookInfo(lib); break; case 3: CmdlineAddBookStock(lib); break; case 4: CmdlineRemoveBookStock(lib); break; case 5: lib.ShowAllBooks(); break; case 6: lib.ShowStatistics(); break; case 7: CmdlineAddReader(lib); break; case 8: CmdlineResetReaderInfo(lib); break; case 9: CmdlineBorrowBook(lib); break; case 10: CmdlineReturnBook(lib); break; case 11: lib.ShowAllReaders(); break; case 12: CmdlineShowBookRanking(lib); break; case 13: CmdlineShowBookType(lib); break; case 14: CmdlineSave(lib); break; case 15: CmdlineLoad(lib); break; case 16: CmdlineShowBookHistory(lib); break; default: std::cout << "无效选项!" << std::endl; } } std::cout << "已退出程序" << std::endl; return 0; #else // 测试 LibraryManager lib; // 单本添加(便捷) lib.AddBook("978-7-115-49250-0", "C++ Primer Plus", "Stephen Prata", "计算机", 50); lib.AddBook("978-7-115-49250-1", "C Primer Plus", "Stephen Prata", "计算机", 100); lib.ShowStatistics(); // 批量添加 lib.AddBooks({ {"978-7-111-40701-4", "Effective Modern C++", "Scott Meyers", "计算机", 20}, {"978-0-13-110362-7", "The C Programming Language", "Brian Kernighan", "计算机", 15}, {"978-7-302-15398-2", "Design Patterns", "GoF", "计算机", 10}, }); lib.ShowStatistics(); lib.AddReader(Reader(1,"leo",10)); lib.AddReader(Reader(2,"qq",10)); lib.ShowAllBooks(); // 借书 lib.BorrowBook(1,"978-7-111-40701-4"); lib.BorrowBook(2,"978-7-115-49250-1"); lib.BorrowBook(2,"978-0-13-110362-7"); lib.BorrowBook(2,"978-7-115-49250-0"); lib.ShowAllBooks(); // 还书 lib.ReturnBook(1,"978-7-111-40701-4"); lib.ReturnBook(2,"978-7-115-49250-1"); lib.ShowAllBooks(); lib.ShowAllReaders(); lib.ShowStatistics(); #endif }pch.h 代码
#pragma once #include <iostream> // cin, cout #include <string> // string #include <vector> // vector #include <fstream> // ifstream, ofstream #include <sstream> // stringstream #include <algorithm> // sort, find #include <map> // map #include <ctime> // time, localtime #include <iomanip> // put_time #include <csignal> // signal