// main.cpp // Paradeigma gia arxeia tyxaias prospelasisis me fixed-width eggrafes // Arxeio: students.txt (id 5, fName 20, sName 30, grade 4, + newline) #include #include #include #include #include #include using namespace std; struct Student { string id; // 5 string fName; // 20 string sName; // 30 double grade; // 0..10 me 1 dekadiko }; static const int DATA_LEN = 59; // 5+20+30+4 static int g_recordSize = 60; // DATA_LEN + newlineLen (1 i 2) static string g_newline = "\n"; // "\n" i "\r\n" // ----------------------------- // Helpers // ----------------------------- static string rtrim(const string& s) { size_t end = s.find_last_not_of(' '); if (end == string::npos) return ""; return s.substr(0, end + 1); } static string fitLeft(const string& s, size_t width) { if (s.size() >= width) return s.substr(0, width); return s + string(width - s.size(), ' '); } static string gradeToField(double g) { // width 4, 1 dekadiko (px 9.8, 10.0, 0.0) ostringstream oss; oss << fixed << setprecision(1) << g; string gs = oss.str(); // px "9.8" i "10.0" if (gs.size() > 4) gs = gs.substr(0, 4); // left-align se 4 chars, opote "8.5 " ant gia " 8.5" return fitLeft(gs, 4); } static bool detectRecordLayout(const string& path) { ifstream file(path, ios::binary); if (!file) { cerr << "Sfalma: Den mporei na anoiksei to arxeio: " << path << "\n"; return false; } string line; if (!getline(file, line)) { cerr << "Sfalma: To arxeio einai adeio.\n"; return false; } // Se Windows, to getline afairei to '\n' alla mporei na meinei '\r' bool hasCR = (!line.empty() && line.back() == '\r'); if (hasCR) line.pop_back(); if ((int)line.size() != DATA_LEN) { cerr << "Proeidopoiisi: I proti grammi den exei " << DATA_LEN << " xaraktires (exei " << line.size() << "). Ta offsets mporei na min einai akrivi.\n"; } g_newline = hasCR ? "\r\n" : "\n"; g_recordSize = DATA_LEN + (hasCR ? 2 : 1); return true; } static string formatRecord(const Student& s) { // Pedia fixed width string rec; rec.reserve(DATA_LEN + g_newline.size()); rec += fitLeft(s.id, 5); rec += fitLeft(s.fName, 20); rec += fitLeft(s.sName, 30); rec += gradeToField(s.grade); rec += g_newline; return rec; } static bool fileHasRecord(ifstream& file, int recNo) { if (recNo <= 0) return false; file.seekg(0, ios::end); streamoff size = file.tellg(); streamoff need = (streamoff)recNo * (streamoff)g_recordSize; return size >= need; } static Student inputStudentFromUser() { Student s; cout << "Dose ID (mexri 5 xaraktires): "; cin >> s.id; cin.ignore(numeric_limits::max(), '\n'); cout << "Dose onoma (First Name, mexri 20): "; getline(cin, s.fName); cout << "Dose epitheto (Surname, mexri 30): "; getline(cin, s.sName); cout << "Dose vathmo (0.0 ews 10.0 me 1 dekadiko): "; cin >> s.grade; // Kanonopoiisi vathmou if (s.grade < 0.0) s.grade = 0.0; if (s.grade > 10.0) s.grade = 10.0; return s; } static void printStudent(const Student& s) { cout << "ID: " << rtrim(s.id) << "\n"; cout << "First Name: " << rtrim(s.fName) << "\n"; cout << "Surname: " << rtrim(s.sName) << "\n"; cout << "Grade: " << fixed << setprecision(1) << s.grade << "\n"; } // ========================================================= // synartiseis diaxeirishs // ========================================================= // 1) readStudentAt(int recordNumber) Student readStudentAt(int recordNumber) { Student s; ifstream file("..\\students.txt", ios::binary); if (!file) { cerr << "Sfalma: Den mporei na anoiksei to students.txt\n"; return s; } // Elegxos yparxis eggrafis if (!fileHasRecord(file, recordNumber)) { cerr << "Sfalma: Den yparxei eggrafi me arithmo " << recordNumber << "\n"; return s; } streamoff offset = (streamoff)(recordNumber - 1) * (streamoff)g_recordSize; file.seekg(offset, ios::beg); string buf(DATA_LEN, '\0'); file.read(&buf[0], DATA_LEN); if (!file) { cerr << "Sfalma: Apotyxia anagnosis eggrafis.\n"; return s; } s.id = buf.substr(0, 5); s.fName = buf.substr(5, 20); s.sName = buf.substr(25, 30); // grade field (4 chars), stod agnoei leading/trailing spaces string gfield = buf.substr(55, 4); try { s.grade = stod(gfield); } catch (...) { s.grade = 0.0; } return s; } // 2) add(const Student&) bool add(const Student& st) { ofstream file("..\\students.txt", ios::binary | ios::app); if (!file) { cerr << "Sfalma: Den mporei na anoiksei to students.txt gia prosthiki.\n"; return false; } string rec = formatRecord(st); file.write(rec.c_str(), (streamsize)rec.size()); if (!file) { cerr << "Sfalma: Apotyxia eggrafis sto arxeio.\n"; return false; } return true; } // 3) replace(int recNo, const Student& replacement) void replace(int recNo, const Student& replacement) { fstream file("..\\students.txt", ios::binary | ios::in | ios::out); if (!file) { cerr << "Sfalma: Den mporei na anoiksei to students.txt gia tropopoiisi.\n"; return; } // Elegxos yparxis eggrafis file.seekg(0, ios::end); streamoff size = file.tellg(); streamoff need = (streamoff)recNo * (streamoff)g_recordSize; if (recNo <= 0 || size < need) { cerr << "Sfalma: Den yparxei eggrafi me arithmo " << recNo << "\n"; return; } streamoff offset = (streamoff)(recNo - 1) * (streamoff)g_recordSize; file.seekp(offset, ios::beg); string rec = formatRecord(replacement); // Grafoyme mono ta DATA_LEN bytes sto idio offset, // kai to newline (1 i 2 bytes) meta, wste na meinei idio recordSize. file.write(rec.c_str(), (streamsize)rec.size()); if (!file) { cerr << "Sfalma: Apotyxia antikatastasis eggrafis.\n"; return; } cout << "Epityxia: I eggrafi " << recNo << " antikatastathike.\n"; } // ----------------------------- // Main (epideiksi me menu) // ----------------------------- int main() { // Prospathoume na "katalavoume" an to arxeio exei \n i \r\n, // gia na exoume swsta offsets. if (!detectRecordLayout("..\\students.txt")) { return 1; } int choice = -1; while (choice != 0) { cout << "\n--- MENU ---\n"; cout << "1) Diavase tin n-osti eggrafi (readStudentAt)\n"; cout << "2) Prosthesi neas eggrafis sto telos (add)\n"; cout << "3) Antikatastasi eggrafis (replace)\n"; cout << "0) Eksodos\n"; cout << "Epilekse: "; cin >> choice; if (cin.fail()) { cin.clear(); cin.ignore(numeric_limits::max(), '\n'); cout << "Lathos eisodos. Prospathise ksana.\n"; continue; } if (choice == 1) { int recNo; cout << "Dose arithmo eggrafis: "; cin >> recNo; Student s = readStudentAt(recNo); cout << "\n--- STOIXEIA FOITITI ---\n"; printStudent(s); } else if (choice == 2) { cout << "\nDose stoixeia gia nea eggrafi:\n"; Student s = inputStudentFromUser(); if (add(s)) { cout << "Epityxia: I eggrafi prostethike sto telos.\n"; } else { cout << "Apotyxia: Den prostethike i eggrafi.\n"; } } else if (choice == 3) { int recNo; cout << "Dose arithmo eggrafis gia antikatastasi: "; cin >> recNo; cout << "\nDose stoixeia replacement:\n"; Student repl = inputStudentFromUser(); replace(recNo, repl); } else if (choice == 0) { cout << "Eksodos.\n"; } else { cout << "Mi egkyri epilogi.\n"; } } return 0; }