2012-09-09 73 views
4

我正在嘗試編寫這個程序,它將員工數據庫保存在一個隨機訪問文件中,它必須具有添加員工和刪除員工的功能(通過寫入記錄中的所有空間)。這是迄今爲止我所擁有的,但它並不完全正確。在閱讀員工時,它讀取正確記錄的工資,但讀取下一條記錄的名稱。另外,當我刪除最後一條記錄並在該記錄中添加一名員工時,我無法查看員工信息,但我得到一個異常錯誤。隨機訪問文件無法正常工作

我不在這裏尋找解決方案,只是在正確的方向輕推。謝謝。

#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 s a 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; 
} 

好的,這裏是新的和改進的(好吧,我認爲是)代碼。我遇到的唯一問題是添加員工時,我可以讓程序將其添加到第一個打開的記錄中,但如果沒有打開的記錄,我似乎無法將其添加到文件沒有搞亂添加到第一個空記錄。我的意思是,如果有空記錄,它會將該員工添加到記錄中,但如果沒有空記錄,則不會將該員工添加到文件末尾。如果我添加代碼以添加到文件末尾,會發生以下兩件事之一:要麼添加到空記錄中,要麼請求另一名員工並將其添加到最後,要麼只是跳過空記錄並添加到文件結尾。

不知道我在做什麼錯在這裏,但任何提示將不勝感激。

#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 s a 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; 
} 
+0

順便說一句,C++有像'stod'和'strtod'這樣的將字符串轉換爲雙精度的東西。不需要自己做。 – chris

+0

@chris我更喜歡,並建議,使用字符串流。 strtod的錯誤處理已經被嚴重打擊了。在符合POSIX標準的編譯器上可以正確使用它,但很難。並非所有的編譯器符合POSIX標準:我的GCC標準庫實現(在OS X上)使用無效的錯誤代碼。 –

+0

@KonradRudolph,不錯,我希望標準會採用boost的詞法轉換。我在一個問題中討論'stoi'的確很愉快。 – chris

回答

1

您撥打read_employee(fs)兩次。首先讀取你想要的記錄,第二個讀取下一個(標準沒有指定哪個是'第一個')。

+0

謝謝,我現在看到代碼中特定部分的問題,非常感謝幫助。 –

0

看來你永遠不會在add_employee中添加行結束符,並且read_employee被調用兩次。只需緩存該函數的結果。

我知道這只是作業,但我認爲你可以改進這個程序。

  1. 需要將數據庫保留爲運行時的文件嗎?您可以將整個文件讀入Employee數組,並在最後重寫。它不會限制員工姓名的長度。

  2. 該程序不是跨平臺的。您不應該依賴文件大小來確定數據庫中的條目數,因爲行終止符因操作系統而異。相反,請全部閱讀並統計條目。

  3. 只有windows有'暫停'程序。爲了達到同樣的效果,只需讀取stdin並在程序結束時忽略輸入。

+0

我看到調用read_employee()的問題。我更改了代碼,以便read_employee中的數據存儲在臨時Employee對象中,然後使用Employee方法顯示數據。感謝您指出了這一點。 –

+0

我想我可以將所有的數據讀入數組,編輯數據,然後寫入文件,我會研究這個。不確定在作業到期之前我會完成它,但這對我來說是一個學習練習。感謝您的建議! –