案例分析:隨機訪問文件

隨機訪問文件

任務:寫一個通用程序,爲任何類型的記錄生成隨機訪問文件。該程序運行後生成了一個包含個人記錄的文件,每條記錄由5個數據成員(社會安全號碼、姓名、所在城市、出生年份以及薪水)組成,該程序還生成了一個存儲學生記錄的學生文件,學生記錄的數據成員與個人紀錄相同,另外還增加了學院專業,再次使用了繼承。
此案例分析中,通用的隨機訪問文件程序能夠將新記錄插入文件,在文件中查找記錄,還可以修改記錄。文件名由用戶提供,如果沒有找到該文件,就新建一個;否則,打開文件進行讀寫。

#pragma once
#ifndef PERSONAL
#define PERSONAL
#include<fstream> //用fstream輸入輸出類來讀寫文件
#include<cstring>
using namespace std;
class Personal //個人記錄類
{
public:
 Personal();
 Personal(char*, char*, char*, int, long);
 void writeToFile(fstream&) const;
 void readFromFile(fstream&);
 void readKey();
 int size() const {
  return 9 + nameLen + cityLen + sizeof(year) + sizeof(salary);
 }
 bool operator==(const Personal& pr) const { //重載==運算符,用於後面判斷兩個成員是否爲同一人
  return strncmp(pr.SSN, SSN, 9) == 0;       //這裏的判斷只需判斷SSN即可,因爲每個人的SSN都是獨一無二的
 }
protected:
 const int nameLen, cityLen;
 char SSN[10], *name, *city;
 int year;
 long salary;
 ostream& writeLegibly(ostream&);
 friend ostream& operator<<(ostream& out, Personal& pr) {
  return pr.writeLegibly(out);
 }
 istream& readFromComsole(istream&);
 friend istream& operator>>(istream& in, Personal& pr) {
  return pr.readFromComsole(in);
 }
};
#endif // !PERSONAL

下面是person類函數的具體實現

#include "Personal.h"
#include<iostream>
Personal::Personal() :nameLen(10), cityLen(10) {
 name = new char[nameLen + 1]; //別忘記字符串是以標誌位'\0'結束的
 city = new char[cityLen + 1];
}
Personal::Personal(char *ssn, char *n, char *c, int y, long s) : 
 nameLen(10), cityLen(10) {
 name = new char[nameLen + 1];
 city = new char[cityLen + 1];
 strcpy(SSN, ssn);
 strcpy(name, n);
 strcpy(city, c);
 year = y;
 salary = s;
}
void Personal::writeToFile(fstream& out) const {
 out.write(SSN, 9);
 out.write(name, nameLen);
 out.write(city, cityLen);
 out.write(reinterpret_cast<const char*>(&year), sizeof(int)); //這裏需要把整型變量轉成常量指針
 out.write(reinterpret_cast<const char*>(&salary), sizeof(int));
}
void Personal::readFromFile(fstream& in) {
 in.read(SSN, 9);
 in.read(name, nameLen);
 in.read(city, cityLen);
 in.read(reinterpret_cast<char*>(&year), sizeof(int));
 in.read(reinterpret_cast<char*>(&salary), sizeof(int));
}
void Personal::readKey() {
 char s[80];
 cout << "Enter SSN: ";
 cin.getline(s, 80);
 strncpy(SSN, s, 9);
}
ostream& Personal::writeLegibly(ostream& out) { //重載輸出運算符
 SSN[9] = name[nameLen] = city[cityLen] = '\0';
 out << "SSN=" << SSN << ",name=" << name
  << ",city=" << city << ",year=" << year
  << ",salary=" << salary;
 return out;
}
istream& Personal::readFromComsole(istream& in) { //重載輸入運算符
 SSN[9] = name[nameLen] = city[cityLen] = '\0';
 char s[80];
 cout << "SSN: ";
 in.getline(s, 80);
 strncpy(SSN, s, 9);
 cout << "Name: ";
 in.getline(s, 80);
 strncpy(name, s, nameLen);
 cout << "City: ";
 in.getline(s, 80);
 strncpy(city, s, cityLen);
 cout << "Birthyear: ";
 in >> year;
 cout << "Salary: ";
 in >> salary;
 in.ignore();
 return in;
}

接下來是學生類的實現,從要求中我們可以知道學生類是person類的派生,所以student類只需要繼承person類,增加額外的數據成員並重載某些類函數即可。

#ifndef STUDENT
#define STUDENT
#include "personal.h"
class Student : public Personal {
public:
    Student();
    Student(char*,char*,char*,int,long,char*);
    void writeToFile(fstream&) const;
    void readFromFile(fstream&);
    int size() const {
        return Personal::size() + majorLen;
    }
protected:
    char *major;
    const int majorLen;
    ostream& writeLegibly(ostream&);
    friend ostream& operator<<(ostream& out, Student& sr) {
        return sr.writeLegibly(out);
    }
    istream& readFromConsole(istream&);
    friend istream& operator>>(istream& in, Student& sr) {
        return sr.readFromConsole(in);
    }
};
#endif

接下來是student某些類函數的重寫

#include "student.h"
#pragma warning(disable : 4996) 
Student::Student() : majorLen(10) {
    Personal();
    major = new char[majorLen+1];
}
Student::Student(char *ssn, char *n, char *c, int y, long s, char *m) :
        majorLen(11) {
    Personal(ssn,n,c,y,s);
    major = new char[majorLen+1];
    strcpy(major,m);
}
void Student::writeToFile(fstream& out) const {
    Personal::writeToFile(out);
    out.write(major,majorLen);
}
void Student::readFromFile(fstream& in) {
    Personal::readFromFile(in);
    in.read(major,majorLen);
}
ostream& Student::writeLegibly(ostream& out) {
    Personal::writeLegibly(out);
    major[majorLen] = '\0';
    out << ", major = " << major;
    return out;
}
istream& Student::readFromConsole(istrieam& in) {
    Personal::readFromConsole(in);
    char s[80];
    cout << "Major: ";
    in.getline(s,80);
    strncpy(major,s,9);
    return in;
}

有了兩個需要記錄的類,接下來咱們需要使用一個Database去記錄person類或者student類,並實現要求的隨機訪問文件

#ifndef DATABASE
#define DATABASE
template<class T>
class Database {
public:
    Database();
    void run();
private:
    fstream database;
    char fName[20];
    ostream& print(ostream&); //輸出文件記錄內容,方便用戶查看
    void add(T&); //在文件尾部追加記錄
    bool find(const T&); //確定記錄是否在文件中。
    void modify(const T&); //更新存儲在特定記錄中的信息。
    friend ostream& operator<<(ostream& out, Database& db) {
        return db.print(out);
    }
};
#endif

Database類函數具體形式以及程序運行測試

#include "personal.h"
#include "student.h"
#include "database.h"
template<class T>
Database<T>::Database() {
}
template<class T>
void Database<T>::add(T& d) {
    database.open(fName,ios::in|ios::out|ios::binary);
    database.clear();
    database.seekp(0,ios::end);
    d.writeToFile(database);
    database.close();
}
template<class T>
void Database<T>::modify(const T& d) {
    T tmp;
    database.open(fName,ios::in|ios::out|ios::binary);
    database.clear();
    while (!database.eof()) {
        tmp.readFromFile(database);
        if (tmp == d) {  // overloaded ==
             cin >> tmp; // overloaded >>
             database.seekp(-d.size(),ios::cur);
             tmp.writeToFile(database);
             database.close();
             return;
        }
    }
    database.close();
    cout << "The record to be modified is not in the database\n";
}
template<class T>
bool Database<T>::find(const T& d) {
    T tmp;
    database.open(fName,ios::in|ios::binary);
    database.clear();
    while (!database.eof()) {
        tmp.readFromFile(database);
        if (tmp == d) { // overloaded ==
            database.close();
            return true;
        }
    }
    database.close();
    return false;
}
template<class T>
ostream& Database<T>::print(ostream& out) {
    T tmp;
    database.open(fName,ios::in|ios::binary);
    database.clear();
    while (true) { 
        tmp.readFromFile(database);
        if (database.eof())
            break;
        out << tmp << endl; // overloaded <<
    }
    database.close();
    return out;
}
template<class T>
void Database<T>::run() {
    cout << "File name: ";
    cin >> fName;
    cin.ignore(); // skip '\n';
    database.open(fName,ios::in);
    if (database.fail())
        database.open(fName,ios::out);
    database.close();
    char option[5];
    T rec;
    cout << "1. Add 2. Find 3. Modify a record; 4. Exit\n";
    cout << "Enter an option: ";
    while (cin.getline(option,5)) {
        if (*option == '1') {
             cin >> rec;   // overloaded >>
             add(rec);
        }
        else if (*option == '2') {
             rec.readKey();
             cout << "The record is ";
             if (find(rec) == false)
                 cout << "not ";
             cout << "in the database\n";
        }
        else if (*option == '3') {
             rec.readKey();
             modify(rec);
        }
        else if (*option != '4')
             cout << "Wrong option\n";
        else return;
        cout << *this;   // overloaded <<
        cout << "Enter an option: ";
    }
}
int main() {
    Database<Personal>().run();
//  Database<Student>().run();
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章