파일 기반 데이터 처리 프로그램 구현
프로젝트 개요
이 실습에서는 학생 정보를 관리하는 파일 기반 데이터 처리 프로그램을 구현합니다.
이 프로그램을 통해 파일 입출력, 데이터 구조, 예외 처리 등 C++의 다양한 기능을 실제로 적용해볼 수 있습니다.
요구사항
- 학생 정보(이름, 학번, 성적) 입력 및 파일 저장
- 저장된 학생 정보 조회
- 특정 학생 정보 검색
- 학생 정보 수정 및 삭제
- 전체 학생의 평균 성적 계산
프로그램 구조
먼저 프로그램의 기본 구조를 설계합니다.
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <stdexcept>
struct Student {
std::string name;
int id;
double grade;
};
class StudentManager {
private:
std::string filename;
std::vector<Student> students;
public:
StudentManager(const std::string& file);
void addStudent(const Student& student);
void saveToFile();
void loadFromFile();
void displayAllStudents();
Student* findStudent(int id);
void updateStudent(int id, const Student& newData);
void deleteStudent(int id);
double calculateAverageGrade();
};
주요 함수 구현
생성자
StudentManager::StudentManager(const std::string& file) : filename(file) {
loadFromFile();
}
학생 추가
void StudentManager::addStudent(const Student& student) {
students.push_back(student);
}
파일에 데이터 저장
void StudentManager::saveToFile() {
std::ofstream file(filename);
if (!file) {
throw std::runtime_error("파일을 열 수 없습니다.");
}
for (const auto& student : students) {
file << student.name << "," << student.id << "," << student.grade << "\n";
}
}
파일에서 데이터 로드
void StudentManager::loadFromFile() {
std::ifstream file(filename);
if (!file) {
return; // 파일이 없으면 무시
}
students.clear();
std::string line;
while (std::getline(file, line)) {
Student student;
size_t pos = 0;
std::string token;
pos = line.find(",");
student.name = line.substr(0, pos);
line.erase(0, pos + 1);
pos = line.find(",");
student.id = std::stoi(line.substr(0, pos));
line.erase(0, pos + 1);
student.grade = std::stod(line);
students.push_back(student);
}
}
모든 학생 정보 표시
void StudentManager::displayAllStudents() {
for (const auto& student : students) {
std::cout << "이름: " << student.name
<< ", 학번: " << student.id
<< ", 성적: " << student.grade << std::endl;
}
}
학생 검색
Student* StudentManager::findStudent(int id) {
for (auto& student : students) {
if (student.id == id) {
return &student;
}
}
return nullptr;
}
학생 정보 수정
void StudentManager::updateStudent(int id, const Student& newData) {
Student* student = findStudent(id);
if (student) {
*student = newData;
} else {
throw std::runtime_error("학생을 찾을 수 없습니다.");
}
}
학생 정보 삭제
void StudentManager::deleteStudent(int id) {
auto it = std::remove_if(students.begin(), students.end(),
[id](const Student& s) { return s.id == id; });
if (it != students.end()) {
students.erase(it, students.end());
} else {
throw std::runtime_error("학생을 찾을 수 없습니다.");
}
}
평균 성적 계산
double StudentManager::calculateAverageGrade() {
if (students.empty()) {
return 0.0;
}
double sum = 0.0;
for (const auto& student : students) {
sum += student.grade;
}
return sum / students.size();
}
메인 프로그램
int main() {
StudentManager manager("students.txt");
try {
// 학생 추가
manager.addStudent({"Alice", 1001, 85.5});
manager.addStudent({"Bob", 1002, 92.0});
manager.addStudent({"Charlie", 1003, 78.5});
// 파일에 저장
manager.saveToFile();
// 모든 학생 정보 표시
std::cout << "모든 학생 정보:" << std::endl;
manager.displayAllStudents();
// 학생 검색
int searchId = 1002;
Student* found = manager.findStudent(searchId);
if (found) {
std::cout << "\n학번 " << searchId << "인 학생 정보:" << std::endl;
std::cout << "이름: " << found->name << ", 성적: " << found->grade << std::endl;
}
// 학생 정보 수정
manager.updateStudent(1001, {"Alice Updated", 1001, 88.0});
// 학생 삭제
manager.deleteStudent(1003);
// 변경 사항 저장
manager.saveToFile();
// 평균 성적 계산
std::cout << "\n평균 성적: " << manager.calculateAverageGrade() << std::endl;
} catch (const std::exception& e) {
std::cerr << "오류 발생: " << e.what() << std::endl;
}
return 0;
}
에러 처리
프로그램 전체에 걸쳐 try-catch 블록을 사용하여 예외를 처리합니다. 파일 입출력, 데이터 변환, 학생 검색 등에서 발생할 수 있는 예외를 고려해야 합니다.
성능 최적화
- 대용량 데이터 처리를 위해 버퍼링 기법을 적용할 수 있습니다.
- 파일 입출력 횟수를 최소화하기 위해 변경 사항을 메모리에 누적했다가 한 번에 저장할 수 있습니다.
- 학생 검색 성능 향상을 위해
std::map
이나std::unordered_map
을 사용할 수 있습니다.
확장 기능
- 정렬 기능 : 이름, 학번, 성적 기준으로 학생 목록을 정렬합니다.
- 통계 기능 : 최고/최저 성적, 표준편차 등을 계산합니다.
- 백업 및 복원 기능 : 데이터의 안전한 보관을 위한 기능을 추가합니다.
연습 문제
- 현재 프로그램을 확장하여 과목별 성적을 관리할 수 있도록 수정하세요.
- 간단한 명령줄 인터페이스를 구현하여 사용자가 대화식으로 프로그램을 조작할 수 있게 만드세요.
- 학생 정보의 유효성을 검사하는 기능을 추가하세요. (예 : 학번 중복 체크, 성적 범위 확인 등)
참고자료
- "Effective C++" by Scott Meyers (항목 23 : 멤버 함수보다는 비멤버 비프렌드 함수를 선호하자)
- "C++ Primer" by Stanley B. Lippman, Josée Lajoie, and Barbara E. Moo (Chapter 8 : The IO Library)
- C++ Reference - File I/O : File I/O in C++
- C++ Core Guidelines : C++ Core Guidelines
- "Design Patterns : Elements of Reusable Object-Oriented Software" by Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides