From 5e6fa305e44ed42c8011c3630ea6c770592bc7e3 Mon Sep 17 00:00:00 2001 From: unlockable Date: Tue, 9 May 2023 14:52:54 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AC=AC=E5=8D=81=E4=B8=80=E5=91=A8=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- OOP/11/Exercise01/exceptions.cpp | 62 ++++++ OOP/11/Exercise01/exceptions.h | 49 +++++ OOP/11/Exercise01/main.cpp | 325 +++++++++++++++++++++++++++++++ OOP/11/Exercise01/teacher.cpp | 107 ++++++++++ OOP/11/Exercise01/teacher.h | 42 ++++ OOP/11/Exercise01/tools.cpp | 38 ++++ OOP/11/Exercise01/tools.h | 3 + 7 files changed, 626 insertions(+) create mode 100644 OOP/11/Exercise01/exceptions.cpp create mode 100644 OOP/11/Exercise01/exceptions.h create mode 100644 OOP/11/Exercise01/main.cpp create mode 100644 OOP/11/Exercise01/teacher.cpp create mode 100644 OOP/11/Exercise01/teacher.h create mode 100644 OOP/11/Exercise01/tools.cpp create mode 100644 OOP/11/Exercise01/tools.h diff --git a/OOP/11/Exercise01/exceptions.cpp b/OOP/11/Exercise01/exceptions.cpp new file mode 100644 index 0000000..c77c3ff --- /dev/null +++ b/OOP/11/Exercise01/exceptions.cpp @@ -0,0 +1,62 @@ +#include "exceptions.h" +#include + +FileOperationException::FileOperationException(std::string _errorName, + std::string _targetFileName) + : errorName(_errorName), targetFileName(_targetFileName){}; + +void FileOperationException::displayExceptionName() { + std::cout << "\033[1;31mException " << this->errorName << "\033[0m" + << std::endl; +} + +FileOpenException::FileOpenException(std::string _targetFileName) + : FileOperationException("FileOpenException", _targetFileName){}; + +void FileOpenException::displayDetailedInformation() { + this->displayExceptionName(); + std::cout << "Failed to open file named " << this->targetFileName + << std::endl; +} + +FileRWException::FileRWException(std::string _errorName, + std::string _targetFileName, + RWMode _readWriteMode) + : FileOperationException(_errorName, _targetFileName), + readWriteMode(_readWriteMode){}; + +std::string FileRWException::getRWMode() { + switch (this->readWriteMode) { + case read: + return "Read"; + break; + case write: + return "Write"; + break; + case readWrite: + return "Read/Write"; + break; + default: + return "Unknown"; + } +} + +FileReadException::FileReadException(std::string _targetFilename, + RWMode _readWriteMode) + : FileRWException("FileReadException", _targetFilename, _readWriteMode){}; + +void FileReadException::displayDetailedInformation() { + this->displayExceptionName(); + std::cout << "Read file " << this->targetFileName + << " error. I/O mode: " << this->getRWMode() << std::endl; +} + +FileWriteException::FileWriteException(std::string _targetFilename, + RWMode _readWriteMode) + : FileRWException("FileWriteException", _targetFilename, _readWriteMode){}; + +void FileWriteException::displayDetailedInformation() { + this->displayExceptionName(); + std::cout << "Write file " << this->targetFileName + << " error. I/O mode: " << this->getRWMode() << std::endl; +} \ No newline at end of file diff --git a/OOP/11/Exercise01/exceptions.h b/OOP/11/Exercise01/exceptions.h new file mode 100644 index 0000000..2033f15 --- /dev/null +++ b/OOP/11/Exercise01/exceptions.h @@ -0,0 +1,49 @@ +#include + +enum RWMode { read, write, readWrite, unknown }; + +class FileOperationException { +private: + std::string errorName; + +protected: + std::string targetFileName; + +public: + FileOperationException( + std::string _errorName = "GeneralFileOperationException", + std::string _targetFileName = ""); + void displayExceptionName(); + virtual void displayDetailedInformation() = 0; +}; + +class FileOpenException : public FileOperationException { +public: + FileOpenException(std::string _targetFileName); + virtual void displayDetailedInformation(); +}; + +class FileRWException : public FileOperationException { +protected: + RWMode readWriteMode; + + std::string getRWMode(); + +public: + FileRWException(std::string _errorName = "GeneralFileReadWriteException", + std::string _targetFileName = "", + RWMode _readWriteMode = unknown); + virtual void displayDetailedInformation() = 0; +}; + +class FileReadException : public FileRWException { +public: + FileReadException(std::string _targetFileName, RWMode _readWriteMode); + virtual void displayDetailedInformation(); +}; + +class FileWriteException : public FileRWException { +public: + FileWriteException(std::string _targetFileName, RWMode _readWriteMode); + virtual void displayDetailedInformation(); +}; \ No newline at end of file diff --git a/OOP/11/Exercise01/main.cpp b/OOP/11/Exercise01/main.cpp new file mode 100644 index 0000000..b2d2e2b --- /dev/null +++ b/OOP/11/Exercise01/main.cpp @@ -0,0 +1,325 @@ +#include "exceptions.h" +#include "teacher.h" +#include "tools.h" +#include +#include +#include + +using std::cin; +using std::cout; +using std::endl; +using std::flush; + +enum workmode { + createFile = 1, + appendData, + changeData, + searchData, + displayAll, + quit +}; + +workmode displayMainMenu() { + int userSelection; + + cout << setMiddle(62, "+", "") << endl; + cout << "+" + << setMiddle(60, " ", "Contoso Company Employee Management System") + << "+" << endl; + cout << setMiddle(62, "+", "") << endl; + + cout << "\n"; + + cout << setMiddle(60, " ", "Main menu") << "\n"; + cout << setMiddle(60, " ", "1. Import data") << "\n"; + cout << setMiddle(60, " ", "2. Append data") << "\n"; + cout << setMiddle(60, " ", "3. Change data") << "\n"; + cout << setMiddle(60, " ", "4. Search data") << "\n"; + cout << setMiddle(60, " ", "5. Display all") << "\n"; + cout << setMiddle(60, " ", "6. Quit ") << endl; + + do { + cout << "\nPlease select: "; + cin >> userSelection; + if (cin.fail()) { + cin.clear(); + cin.ignore(); + userSelection = 0; + } + if (1 <= userSelection && userSelection <= (int)quit) { + return (workmode)userSelection; + } + cout << "Unknown selection. Try again." << endl; + } while (true); +} + +void doCreateFile() { + std::string fileName; + cout << "New file name (file with same name will be replaced): " << flush; + cin >> fileName; + std::fstream outfile(fileName, std::ios::out | std::ios::binary); + outfile.exceptions(std::ios_base::failbit | std::ios_base::badbit); + if (!outfile.is_open()) { + throw(FileOpenException(fileName)); + } + + cout << "Start reading in new Teacher data. How many do you want to create?" + << endl; + int count = 1, total = 0; + total = askValidInt(); + + while (count <= total) { + cout << "\033[1;32mTeacher " << count << "/" << total << ":\033[0m" + << endl; + Teacher aTeacher(true); + try { + outfile.write((char *)&aTeacher, sizeof(aTeacher)); + } + catch (std::ios_base::failure) { + throw(FileWriteException(fileName, write)); + } + cout << "Created " << count++ << " new teacher. (Total " << total << ")" + << endl; + } + try { + outfile.write((char *)&total, sizeof(total)); + } + catch (std::ios_base::failure) { + throw(FileWriteException(fileName, write)); + }; + outfile.close(); +} + +void doAppendData() { + std::string fileName; + cout << "File name: " << flush; + cin >> fileName; + std::fstream fileObj(fileName, + std::ios::in | std::ios::out | std::ios::binary); + fileObj.exceptions(std::ios_base::failbit | std::ios_base::badbit); + if (!fileObj.is_open()) { + throw(FileOpenException(fileName)); + } + + int total; + fileObj.seekp(-sizeof(int), std::ios::end); + try { + fileObj.read((char *)&total, sizeof(int)); + } + catch (std::ios_base::failure) { + throw(FileReadException(fileName, readWrite)); + } + cout << "\033[1;34mThere are already " << total + << " teacher(s) recorded in this file.\033[0m" << endl; + fileObj.seekp(sizeof(Teacher) * total); + + cout << "Start reading in new Teacher data. How many do you want to create?" + << endl; + int newTeacherTotal, newTeacherCount = 1; + newTeacherTotal = askValidInt(); + total += newTeacherTotal; + while (newTeacherCount <= newTeacherTotal) { + cout << "\033[1;32mNew teacher " << newTeacherCount << "/" + << newTeacherTotal << ":\033[0m" << endl; + Teacher aTeacher(true); + try { + fileObj.write((char *)&aTeacher, sizeof(aTeacher)); + } + catch (std::ios_base::failure) { + throw(FileWriteException(fileName, readWrite)); + } + cout << "Created " << newTeacherCount++ << " new teacher. (Total " + << newTeacherTotal << " new teachers)" << endl; + } + try { + fileObj.write((char *)&total, sizeof(int)); + } + catch (std::ios_base::failure) { + throw(FileWriteException(fileName, readWrite)); + } + fileObj.close(); +} + +void doChangeData() { + std::string fileName; + cout << "File name:" << flush; + cin >> fileName; + std::fstream fileObj(fileName, + std::ios::in | std::ios::out | std::ios::binary); + if (!fileObj.is_open()) { + throw(FileOpenException(fileName)); + } + + int total; + fileObj.seekg(-sizeof(int), std::ios::end); + try { + fileObj.read((char *)&total, sizeof(int)); + } + catch (std::ios_base::failure) { + throw(FileReadException(fileName, readWrite)); + } + + cout << "\033[1;34mThere are " << total + << " teacher(s) recorded in this file. Which one do you want to " + "change?\033[0m" + << endl; + int userSelect = 0; + while (true) { + userSelect = askValidInt(); + if (userSelect < 1 || userSelect > total) { + cout << "Out of bounds. Try again: " << flush; + continue; + } + break; + } + + Teacher aTeacher; + fileObj.seekg(sizeof(Teacher) * (userSelect - 1)); + try { + fileObj.read((char *)&aTeacher, sizeof(Teacher)); + } + catch (std::ios_base::failure) { + throw(FileReadException(fileName, readWrite)); + } + + cin >> aTeacher; + + fileObj.seekg(sizeof(Teacher) * (userSelect - 1)); + try { + fileObj.write((char *)&aTeacher, sizeof(Teacher)); + } + catch (std::ios_base::failure) { + throw(FileWriteException(fileName, readWrite)); + } + fileObj.close(); +} + +void doSearchData() { + std::string fileName; + cout << "File name: " << flush; + cin >> fileName; + std::fstream fileObj(fileName, std::ios::in | std::ios::binary); + if (!fileObj.is_open()) { + throw(FileOpenException(fileName)); + } + + int total; + fileObj.seekg(-sizeof(int), std::ios::end); + try { + fileObj.read((char *)&total, sizeof(int)); + } + catch (std::ios_base::failure) { + throw(FileReadException(fileName, readWrite)); + } + + Teacher *allTeachers = new Teacher[total]; + fileObj.seekg(0); + try { + fileObj.read((char *)allTeachers, total * sizeof(Teacher)); + } + catch (std::ios_base::failure) { + throw(FileReadException(fileName, readWrite)); + } + fileObj.close(); + + int targetTeacherNum, matchedTeacherTotal = 0; + int *matchedIndexes = new int[total]; + + cout << "Input your target teacher number: "; + targetTeacherNum = askValidInt(); + + for (int i = 0; i < total; i++) { + if (allTeachers[i].getNumber() == targetTeacherNum) { + matchedIndexes[matchedTeacherTotal++] = i; + } + } + + if (matchedTeacherTotal > 0) { + cout << "\033[1;34mThere are a total of " << matchedTeacherTotal + << " teacher(s) matches your criteria.\033[0m" << endl; + for (int i = 0; i < matchedTeacherTotal; i++) { + cout << "\033[1;32mMatched teacher " << i + 1 << "/" + << matchedTeacherTotal + << " (Position in file: " << matchedIndexes[i] + 1 + << "):\033[0m\n" + << allTeachers[matchedIndexes[i]]; + } + cout << flush; + } + else { + cout << "\033[1;34mNo teacher matched your criteria.\033[0m" << endl; + } +} + +void doDisplayAll() { + std::string fileName; + cout << "File name: " << flush; + cin >> fileName; + std::fstream fileObj(fileName, std::ios::in | std::ios::binary); + if (!fileObj.is_open()) { + throw(FileOpenException(fileName)); + } + + int total; + fileObj.seekg(-sizeof(int), std::ios::end); + try { + fileObj.read((char *)&total, sizeof(int)); + } + catch (std::ios_base::failure) { + throw(FileReadException(fileName, readWrite)); + } + + Teacher *allTeachers = new Teacher[total]; + fileObj.seekg(0); + try { + fileObj.read((char *)allTeachers, total * sizeof(Teacher)); + } + catch (std::ios_base::failure) { + throw(FileReadException(fileName, readWrite)); + } + fileObj.close(); + + cout << "\033[1;34mThere are a total of " << total << " teacher(s).\033[0m" + << endl; + for (int i = 0; i < total; i++) { + cout << "\033[1;32mTeacher " << i + 1 << "/" << total << ":\033[0m\n" + << allTeachers[i]; + } + cout << endl; + delete[] allTeachers; +}; + +int main() { + workmode mode; + bool running = true; + while (running) { + mode = displayMainMenu(); + try { + switch (mode) { + case createFile: + doCreateFile(); + break; + case appendData: + doAppendData(); + break; + case changeData: + doChangeData(); + break; + case searchData: + doSearchData(); + break; + case displayAll: + doDisplayAll(); + break; + case quit: + running = false; + break; + } + } + catch (FileOperationException &e) { + e.displayDetailedInformation(); + cout << "Returning to main menu." << endl; + } + } + return 0; +} \ No newline at end of file diff --git a/OOP/11/Exercise01/teacher.cpp b/OOP/11/Exercise01/teacher.cpp new file mode 100644 index 0000000..817f6de --- /dev/null +++ b/OOP/11/Exercise01/teacher.cpp @@ -0,0 +1,107 @@ +#include "teacher.h" +#include "tools.h" +using std::cin; +using std::cout; +using std::endl; +using std::flush; + +Teacher::Teacher(bool interactive, int _number, std::string _name, + std::string _sex) + : number(_number) { + if (interactive) { + std::string temp; + cout << "Number: " << flush; + this->number = askValidInt(); + + cout << "Name (max 50): " << flush; + cin >> temp; + this->setName(temp); + + cout << "Sex (max 10): " << flush; + cin >> temp; + this->setSex(temp); + return; + } + + this->setName(_name.c_str()); + this->setSex(_name.c_str()); +} + +int Teacher::setNumber(int _num) { + this->number = _num; + return this->number; +} + +std::string Teacher::setName(char _name[]) { + if (strlen(_name) > MAX_TEACHER_NAME_SIZE) { + cout << "\033[1;31mName is longer than " << MAX_TEACHER_NAME_SIZE + << " characters. String will be cut.\033[0m" << endl; + } + strlcpy(Teacher::name, _name, MAX_TEACHER_NAME_SIZE + 1); + std::string result(_name); + return result; +} + +std::string Teacher::setSex(char _sex[]) { + if (strlen(_sex) > MAX_TEACHER_SEX_SIZE) { + cout << "\033[1;31mSex is longer than " << MAX_TEACHER_SEX_SIZE + << " characters. String will be cut.\033[0m" << endl; + } + strlcpy(Teacher::sex, _sex, MAX_TEACHER_NAME_SIZE + 1); + std::string result(_sex); + return result; +} + +std::string Teacher::setName(std::string _name) { + if (_name.length() > MAX_TEACHER_NAME_SIZE) { + cout << "\033[1;31mName is longer than " << MAX_TEACHER_NAME_SIZE + << " characters. String will be cut.\033[0m" << endl; + } + strlcpy(Teacher::name, _name.c_str(), MAX_TEACHER_NAME_SIZE); + return _name; +} + +std::string Teacher::setSex(std::string _sex) { + if (_sex.length() > MAX_TEACHER_SEX_SIZE) { + cout << "\033[1;31mSex is longer than " << MAX_TEACHER_SEX_SIZE + << " characters. String will be cut.\033[0m" << endl; + } + strlcpy(Teacher::sex, _sex.c_str(), MAX_TEACHER_NAME_SIZE); + return _sex; +} + +int Teacher::getNumber() { + return this->number; +} + +std::string Teacher::getName() { + std::string result(this->name); + return result; +} + +std::string Teacher::getSex() { + std::string result(this->sex); + return result; +} + +std::istream &operator>>(std::istream &input, Teacher &teacher) { + cout << "Number (Original: " << teacher.getNumber() << "): " << flush; + teacher.number = askValidInt(); + + cout << "Name (Original: " << teacher.getName() << "), max 50: " << flush; + std::string temp; + cin >> temp; + teacher.setName(temp); + + cout << "Sex (Original: " << teacher.getSex() << "), max 10: " << flush; + cin >> temp; + teacher.setSex(temp); + return input; +} + +std::ostream &operator<<(std::ostream &output, Teacher &teacher) { + cout << "Number: " << teacher.getNumber() << "\n"; + cout << "Name: " << teacher.getName() << "\n"; + cout << "Sex: " << teacher.getSex() << "\n"; + return output; +} \ No newline at end of file diff --git a/OOP/11/Exercise01/teacher.h b/OOP/11/Exercise01/teacher.h new file mode 100644 index 0000000..420a4b5 --- /dev/null +++ b/OOP/11/Exercise01/teacher.h @@ -0,0 +1,42 @@ +#include +#define MAX_TEACHER_NAME_SIZE 50 +#define MAX_TEACHER_SEX_SIZE 10 + +class Teacher { +private: + friend std::istream &operator>>(std::istream &input, Teacher &teacher); + friend std::ostream &operator<<(std::ostream &output, Teacher &teacher); + +protected: + int number; + char name[MAX_TEACHER_NAME_SIZE + 1]; + char sex[MAX_TEACHER_SEX_SIZE + 1]; + +public: + Teacher(bool interactive = false, int _number = 0, std::string _name = "Unknown", + std::string _sex = "Unknown"); + + // 返回更新后的num + int setNumber(int _num); + + // 返回更新后的name + std::string setName(std::string _name); + + // 返回更新后的name + std::string setName(char _name[]); + + // 返回更新后的sex + std::string setSex(std::string _sex); + + // 返回更新后的sex + std::string setSex(char _sex[]); + + // 获取num + int getNumber(); + + // 获取name + std::string getName(); + + // 获取sex + std::string getSex(); +}; \ No newline at end of file diff --git a/OOP/11/Exercise01/tools.cpp b/OOP/11/Exercise01/tools.cpp new file mode 100644 index 0000000..439a4e3 --- /dev/null +++ b/OOP/11/Exercise01/tools.cpp @@ -0,0 +1,38 @@ +#include "tools.h" +#include +using std::cin; +using std::cout; +using std::endl; + +int askValidInt() { + int result = 0; + while (true) { + cin >> result; + if (cin.fail()) { + cin.clear(); + cin.ignore(); + cout << "Please input a valid number." << endl; + continue; + } + break; + } + return result; +} + +std::string setMiddle(int width, std::string fillChar, + std::string originString) { + int len = originString.length(); + if (len >= width) { + return originString; + } + int fill = (width - len) / 2; + std::string result = ""; + for (int i = 0; i < fill; i++) { + result += fillChar; + } + result += originString; + for (int i = result.length(); i < width; i++) { + result += fillChar; + } + return result; +} \ No newline at end of file diff --git a/OOP/11/Exercise01/tools.h b/OOP/11/Exercise01/tools.h new file mode 100644 index 0000000..dce41b5 --- /dev/null +++ b/OOP/11/Exercise01/tools.h @@ -0,0 +1,3 @@ +#include +int askValidInt(); +std::string setMiddle(int width, std::string fillChar, std::string originString); \ No newline at end of file