Random file not working properly

I am trying to write this program that stores the employee database in a random access file, it should have functions for adding employees and deleting employees (by writing all the spaces in the record). This is what I have so far, but it does not work perfectly right. When reading an employee, he reads the salary of the correct record, but the name of the next record. In addition, when I delete the last record and add an employee to this record, I cannot view the information about the employee, I get an exception error.

I'm not looking for a solution here, just a push in the right direction. Thanks.

#include "stdafx.h" #include <iostream> #include <iomanip> #include <fstream> #include <sstream> #include "ccc_empl.h" using namespace std; const int NEWLINE_LENGTH = 2; const int RECORD_SIZE = 30 + 10 + NEWLINE_LENGTH; /** converts a string to a floating-point value @param sa string representing a floating-point value @return the equivalent floating-point value */ double string_to_double(string s) { istringstream instr(s); double x; instr >> x; return x; } /* reads an employee record from the input file @param e the employee @param in the file to read from */ Employee read_employee(istream& in) { string line; getline(in, line); string input_name = line.substr(0, 30); double input_salary = string_to_double(line.substr(30, 10)); Employee e(input_name, input_salary); return e; } /* gets input for an Employee object @param input_name the name of the employee @param input_salary the salary of the employee @param e the Employee object @return returns the Employee object */ Employee input_employee() { string input_name; cout << "Name: "; cin.ignore(); getline(cin, input_name); cout << "Salary: "; double input_salary; cin >> input_salary; Employee e(input_name, input_salary); return e; } /** adds an employee record to a file @param e the employee record to write @param out the file to write to */ void add_employee(Employee e, ostream& out) { out << e.get_name() << setw(30) << fixed << setprecision(2) << e.get_salary(); } /** removes an employee record from a file @param e the employee record to remove @param out the file to remove from */ void remove_employee(ostream& out) { out << " " << setw(42) << fixed << setprecision(2) << " \n"; } int main() { cout << "Please enter the data file name: "; string filename; cin >> filename; fstream fs; fs.open(filename); fs.seekg(0, ios::end); // Go to end of file int nrecord = fs.tellg() / RECORD_SIZE; // determine number of records in the file int menu_input = 0; string input_name; double input_salary = 0; while (menu_input != 4) { cout << "Please enter the record to update: (0 - " << nrecord - 1 << ") exit to quit "; int pos = 0; cin >> pos; if(cin.fail()) { cout << "Exiting..." << endl; system("pause"); return 0; } // menu for user input cout << "\nWhat action would you like to perform?" << endl; cout << "Add employee.....1" << endl; cout << "Remove employee..2" << endl; cout << "View employee....3" << endl; cin >> menu_input; switch(menu_input) { case 1: fs.seekg(pos * RECORD_SIZE, ios::beg); add_employee(input_employee(), fs); break; case 2: fs.seekg(pos * RECORD_SIZE, ios::beg); remove_employee(fs); break; case 3: fs.seekg(pos * RECORD_SIZE, ios::beg); cout << "\nName: " << read_employee(fs).get_name() << "Salary: " << read_employee(fs).get_salary() << endl << endl; break; default: cout << "Invalid entry" << endl; break; } } fs.close(); system("pause"); return 0; } 

Ok, here is a new and improved (well, I think so) code. The only problem I am facing is adding an employee, I can make the program add it to the first open record just fine, but if there are no open records, I cannot force it to add to the end of the file without messing up the addition to the first empty record. I mean, if there is an empty record, it will add an employee to the record, but if there is no empty record, it will not add an employee to the end of the file. If I add the code to be added to the end of the file, one of two things will happen: either it will add to the empty record, then it will request another employee and add it to the end, or it will simply skip the empty record and add the end of the file.

Not sure what I'm doing wrong here, but any tips would be appreciated.

 #include "stdafx.h" #include <iostream> #include <iomanip> #include <fstream> #include <sstream> #include "ccc_empl.h" using namespace std; const int NEWLINE_LENGTH = 2; const int RECORD_SIZE = 30 + 10 + NEWLINE_LENGTH; /** converts a string to a floating-point value @param sa string representing a floating-point value @return the equivalent floating-point value */ double string_to_double(string s) { istringstream instr(s); double x; instr >> x; return x; } /* reads an employee record from the input file @param e the employee @param in the file to read from */ Employee read_employee(istream& in) { string line; getline(in, line); string input_name = line.substr(0, 30); double input_salary = string_to_double(line.substr(30, 10)); Employee e(input_name, input_salary); return e; } /* gets input for an Employee object @param input_name the name of the employee @param input_salary the salary of the employee @param e the Employee object @return returns the Employee object */ Employee input_employee() { string input_name; cout << "Name: "; cin.ignore(); getline(cin, input_name); cout << "Salary: "; double input_salary; cin >> input_salary; Employee e(input_name, input_salary); return e; } /** adds an employee record to a file @param e the employee record to write @param out the file to write to */ void add_employee(Employee e, ostream& out) { out << e.get_name() << setw(10 + 30 - e.get_name().length()) << fixed << setprecision(2) << e.get_salary() << "\n"; } /** removes an employee record from a file @param e the employee record to remove @param out the file to remove from */ void remove_employee(ostream& out) { out << " " << setw(40) << fixed << setprecision(2) << " \n"; } int main() { cout << "Please enter the data file name: "; string filename; cin >> filename; fstream fs; fs.open(filename); fs.seekg(0, ios::end); // Go to end of file int nrecord = fs.tellg() / RECORD_SIZE; // determine number of records in the file int menu_input = 1; string input_name; double input_salary = 0; while (menu_input) { // menu for user input cout << "\nWhat action would you like to perform?" << endl; cout << "Add employee.....1" << endl; cout << "Remove employee..2" << endl; cout << "View employee....3" << endl; cout << "Exit.............4" << endl; cin >> menu_input; if (menu_input == 4) { cout << "\nExiting..." << endl << endl; system("pause"); return 0; } // switch statment to perform selected menu_input task switch(menu_input) { case 1: // adds an employee in the first empty record // or at the end of the file if no records are empty { int count = 0; string s; for (int i = 0; i < nrecord; i++) { fs.seekp(count, ios::beg); getline(fs, s); if (isspace(s[0])) { fs.seekp(count, ios::beg); add_employee(input_employee(), fs); nrecord++; break; }else count += 42; } } break; case 2: { cout << "Please enter the record to remove: (0 - " << nrecord -1 << ") "; int pos = 0; cin >> pos; fs.seekp(pos * RECORD_SIZE, ios::beg); remove_employee(fs); } break; case 3: { cout << "Please enter the record to view: (0 - " << nrecord -1 << ") "; int pos = 0; cin >> pos; fs.seekg(pos * RECORD_SIZE, ios::beg); Employee e(read_employee(fs)); cout << "\nName: " << e.get_name() << "Salary: " << e.get_salary() << endl << endl; } break; default: cout << "Invalid entry" << endl; break; } } fs.close(); system("pause"); return 0; } 
+4
source share
2 answers

You call read_employee(fs) twice. First reads the record you want, the second reads the next (the standard does not indicate which one is "first").

+1
source

It seems you never add a line terminator to add_employee, and read_employee is called twice. Just cache the result of the function.

I know this is just homework, but I think you can improve this program.

  • Do I need to store the database as a file at runtime? You can simply read the entire file into the Employee array and overwrite it at the end. This does not limit the length of employee names.

  • This program is not cross-platform. You do not have to rely on file size to determine the number of records in the database, as line terminators range from os to os. Instead, read everything and count the entries.

  • Only windows have a pause program. To achieve the same effect, just read stdin at the end of the program and ignore the input.

0
source

Source: https://habr.com/ru/post/1433242/


All Articles