C++笔记打卡第14天(文件管理、职工操作系统)

1.文本文件(写文件)

文件类型分为两种:

  • 文本文件:文件以文本的ASCII码形式存储在计算机中
  • 二进制文件:文件以文本的二进制形式存储在计算机中,用户一般不能直接读懂它

操作文件的三大类

  • ofstream:写操作
  • ifstream:读操作
  • fstream:读写操作

写文件:

  • 包含头文件 #include <fstream>
  • 创建流对象 ofstream ofs;
  • 打开文件 ofs.open(”文件路径”,打开方式);
  • 写数据 ofs<<”写入的数据”;
  • 关闭文件 ofs.close();
文件打开方式解释
ios::in为读文件而打开文件
ios::out为写文件而打开文件
ios::ate初始位置:文件尾
ios::app追加方式写文件
ios::trunc如果文件存在先删除,再创建
ios::binary二进制方式

文件打开方式可以配合使用,利用 | 操作符。如用二进制方式写文件 ios::binary | ios::out

void test01()
{
    // 1.文件操作必须包含头文件fsream
    // 2.创建流对象
    ofstream ofs;
    // 3.制定打开方式
    ofs.open("test.txt", ios::out);
    // 4.写<<内容
    ofs << "张三" << endl;
    ofs << "男" << endl;
    ofs << "18" << endl;
    // 5.关闭文件
    ofs.close();
}

2.文本文件(读文件)

读文件:

  • 包含头文件 #include <fstream>
  • 创建流对象 ifstream ifs;
  • 打开文件并判断文件是否打卡成功 ifs.open(”文件路径”,打开方式);
  • 读数据
  • 关闭文件 ifs.close();
void test01()
{
    // 1.创建流对象
    ifstream ifs;
    // 2.制定打开方式
    ifs.open("test.txt", ios::in);
    if (!ifs.is_open())  // 判断文件是否打开成功
    {
        cout << "文件打开失败" << endl;
        return;
    }
    // 3.读数据
    char buf[1024] = {0};
    while(ifs >> buf)
    {
        cout << buf << endl;
    }
    // 一行一行读
    char buf[1024] = {0};
    while(ifs.getline(buf, sizeof(buf)))
    {
        cout << buf << endl;
    }
    // 一行一行读
    string buf;
    while(getline(ifs, buf))
    {
        cout << buf << endl;
    }
    // 一个一个读
    char c;
    while((c = ifs.get()) != EOF)
    {
        //cout << c;
    //}
    
    // 4.关闭文件
    ifs.close();
}

3.二进制文件(写文件)

  • 二进制方式写文件主要利用流对象调用成员write
  • 函数原型:ostream& write(const char* buffer,int len);
class Person
{
public:
    char m_Name[64];
    int m_Age;
};
void test01()
{
    // 1.包含头文件
    // 2.创建流对象
    ofstream ofs;
    // 3.打开文件
    ofs.open("person.txt", ios::out | ios::binary);
    // 4.写文件
    Person p = {"张三", 18};
    ofs.write((const char *)&p, sizeof(Person));
    // 5.关闭文件
    ofs.close();
}

4.二进制文件(写文件)

  • 二进制方式读文件主要利用流对象调用成员函数read
  • 函数原型:istream& read(char *buffer, int len);
class Person
{
public:
    char m_Name[64];
    int m_Age;
};
void test01()
{
    // 1.包含头文件
    // 2.创建流对象
    ifstream ifs;
    // 3.打开文件 判断文件是否打开成功
    ifs.open("person.txt", ios::in | ios::binary);
    if(!ifs.is_open())
    {
        cout << "文件打开失败" << endl;
    }
    // 4.写文件
    Person p;
    ifs.read((char *)&p, sizeof(Person));
    cout << p.m_Name << p.m_Age << endl;
    // 5.关闭文件
    ifs.close();
}

5.职工管理系统

公司中职工分为三类:普通员工、经理、老板,显示信息时,需要显示职工编号、职工姓名、职工岗位、以及职责

  • 普通员工职责:完成经理交给的任务
  • 经理职责:完成老板交给的任务,并下发任务给员工
  • 老板职责:管理公司所有事务

管理系统重需要实现的功能如下:

  • 退出管理程序:退出当前管理系统
  • 增加职工信息:实现批量添加职工功能,将信息录入到文件中,职工信息为:职工编号、姓名、部门编号
  • 显示职工信息:显示公司内部所有职工的信息
  • 删除离职职工:按照编号删除指定的职工
  • 修改职工信息:按照编号修改职工个人信息
  • 查找职工信息:按照职工的编号或者职工的姓名进行查找相关的人员信息
  • 按照编号排序:按照职工编号,进行排序,排序规则由用户指定
  • 清空所有文档:清空文件中记录的所有职工信息(清空前需要再次确认,防止误删)

第一步:实例化管理者对象

创建总执行文件 main.cpp,workerManager.h 和 workerManager.cpp 三个文件。

int main()
{
    // 实例化管理者对象
    WorkerManager wm;
    system("pause");
    return 0;
}

在workerManager.h中设置每一个用到的函数声明:

#pragma once
#include <iostream>

class WorkerManager
{
public:
    WorkerManager(); 
    ~WorkerManager(); 
};

 在workerManager.cpp 里写每一个函数的具体实现:

#include <workerManager.h>

// 构造函数
WorkerManager::WorkerManager()
{
  
}

// 析构函数
WorkerManager::~WorkerManager()
{

}

第二步:创建抽象的员工类别,以及三个派生类(普通员工、经理、老板)

创建 worker.h,设置抽象的员工类别作为基类

#pragma once
#include <iostream>
#include <string>
using namespace std;

class Worker
{
public:
    // 显示个人信息
    virtual void showInfor() = 0;
    // 获取岗位名称
    virtual string showDepartment() = 0;
    int m_id;
    string m_name;
    int m_deptid;
};

在基类基础上创建三种子类,表示三种员工(普通员工、经理、老板)

普通员工 employee.h 每个函数的声明:

#pragma once
#include <iostream>
#include <string>
#include <worker.h>
using namespace std;

class Employee:public Worker
{
public:
    Employee(int id, string name, int deptid);
    virtual void showInfor();
    virtual string showDepartment();
};

普通员工 employee.cpp 每个函数的具体实现:

#include <employee.h>

Employee::Employee(int id, string name, int deptid)
{
    m_name = name;
    m_id = id;
    m_deptid = deptid;
}
void Employee::showInfor()
{
    cout << "职工编号: " << this->m_id;
    cout << "\t职工姓名: " << this->m_name;
    cout << "\t岗位: " << this->showDepartment();
    cout << "\t岗位职责: 完成经理交代的任务" << endl;
}
string Employee::showDepartment()
{
    return string("员工");
}

之后再以同样的方式创建Manage.h , Mangae.cpp, Boss.h, Boss.cpp。

第三步:显示菜单

在workerManager.h中加入:

// 展示菜单
void show_Menu();

在workerManager.cpp中加入:

void WorkerManager::show_Menu()
{
    cout << "*********************************" << endl;
    cout << "*******欢迎使用职工管理系统******" << endl;
    cout << "********0.退出管理程序***********" << endl;
    cout << "********1.增加职工信息***********" << endl;
    cout << "********2.显示职工信息***********" << endl;
    cout << "********3.删除高职职工***********" << endl;
    cout << "********4.修改职工信息***********" << endl;
    cout << "********5.查找职工信息***********" << endl;
    cout << "********6.按照编号排序***********" << endl;
    cout << "********7.清空所有文档***********" << endl;
    cout << "*********************************" << endl;
    cout << endl;
}

第四步:选择为0时退出系统

在workerManager.h中加入声明:

// 退出
void ExitSystem();

在workerManager.cpp中加入具体实现:

void WorkerManager::ExitSystem()
{
    cout << "欢迎下次使用" << endl;
    system("pause");
    exit(0);
}

第五步:选择为1时添加职工

用户在批量创建时,可能会创建不同种类的职工。如果想将所有不同种类的员工都收入到一个数组中,可以将所有员工的指针维护到一个数组里。如果想在程序中维护这个不定长度的数组,可以将数组创建到堆区,并利用Worker **的指针维护。

在workerManager.h中加入声明:

// 记录职工人数
int m_EmpNum;
// 记录职工数组的指针
Worker **m_EmpArray;
void Add_Emp();

在workerManager.cpp中加入具体实现:

void WorkerManager::Add_Emp()
{
    cout << "请输入需要添加的职工的数量:" << endl;
    int addNum = 0;
    cin >> addNum;

    if(addNum > 0)
    {
        int newSize = this->m_EmpNum + addNum; // 新空间人数 = 已经记录的人数 + 新增人数

        // 开辟存放指针的新空间
        Worker** newSpace = new Worker*[newSize];

        // 将已经记录的内容放入新的空间
        if(this->m_EmpArray != NULL)
        {
            for(int i=0; i < this->m_EmpNum; i++)
            {
                newSpace[i] = this->m_EmpArray[i];
            }
        }
        // 添加新数据
        for(int i=0; i<addNum; i++)
        {
            int id;
            string name;
            int deptid;

            cout << "请输入第" << i+1 << "位职工的编号:" << endl;
            cin >> id;
            cout << "请输入第" << i+1 << "位职工的姓名:" << endl;
            cin >> name;
            cout << "请选择第" << i+1 << "位职工的岗位(1-普通员工, 2-经理, 3-老板):" << endl;
            cin >> deptid;

            Worker *worker = NULL;
            switch(deptid)
            {
                case 1:
                    worker = new Employee(id, name, 1);
                    break;
                case 2:
                    worker = new Manager(id, name, 2);
                    break;
                case 3:
                    worker = new Boss(id, name, 3);
                    break;
                default:
                    break;
            }

            // !将新创建的职工指针,保存到数组中
            newSpace[this->m_EmpNum+i] = worker;
        }

        // 释放原有空间
        delete[] this->m_EmpArray;
        // 更新
        this->m_EmpArray = newSpace;
        this->m_EmpNum = newSize;

        // 更新职工不为空的标志
        this->is_Empty = false;

        // 保存数据到文件中
        this->save();
        cout << "成功添加" << addNum << "位员工!" << endl;
    }
    else
    {
        cout << "输入有误" << endl;
    }
    system("pause");
    system("cls");
}

第六步:将信息保存到文本文件中

在workerManager.h中加入声明:

void save();

在workerManager.cpp中加入具体实现:

void WorkerManager::save()
{
    ofstream ofs;
    ofs.open(FILENAME, ios::out);
    for(int i=0; i<this->m_EmpNum; i++)
    {
        ofs << this->m_EmpArray[i]->m_id << " "
        << this->m_EmpArray[i]->m_name << " "
        << this->m_EmpArray[i]->m_deptid << endl;
    }
    ofs.close();
}

第七步:选择为2时显示职工

在workerManager.h中加入声明:

    // 判断文件是否为空(之前是否已经有存入的数据)
    bool is_Empty;
    // 如果有,统计文件中的人数
    int get_EmpNum();
    // 初始化m_EmpArray数组
    void init_Emp();
    // 显示职工
    void show_Emp();

在workerManager.cpp中加入具体实现:(在构造函数中加入三种初始情况,没有初始文件时,有出示文件但没有数据时,有文件且有数据时)对于前两种情况,在构造函数㕜将this->m_EmpNum设为0,this->m_EmpArray设为空。

WorkerManager::WorkerManager()
{
    // 文件不存在时
    ifstream ifs;
    ifs.open(FILENAME, ios::in);
    if(!ifs.is_open())
    {
        cout << "初始员工文件不存在" << endl;
        // 初始化属性
        this->m_EmpNum = 0;
        this->m_EmpArray = NULL;
        this->is_Empty = true; 
        ifs.close(); 
        return;
    }

    // 文件存在且数据为空
    char ch;
    ifs >> ch;
    if(ifs.eof())
    {
        // 代表文件为空
        cout << "初始员工文件为空" << endl;
        // 初始化属性
        this->m_EmpNum = 0;
        this->m_EmpArray = NULL;
        this->is_Empty = true; 
        ifs.close(); 
        return;
    }

    // 文件存在且有数据
    this->is_Empty = false;
    int num = this->get_EmpNum();
    cout << "已存储" << num << "位职工信息" << endl;
    this->m_EmpNum = num;
    this->m_EmpArray = new Worker*[num];
    this->init_Emp();
    
}

对于第三种情况,有文件且有数据,首先求得文件中数据的长度,再将数据初始化到m_EmpArray中:

int WorkerManager::get_EmpNum()
{
    ifstream ifs;
    ifs.open(FILENAME, ios::in);
    int num = 0;
    int id;
    string name;
    int deptid;
    while(ifs >> id && ifs >> name && ifs >> deptid)
    {
        num++;
    }
    return num;
}

void WorkerManager::init_Emp()
{
    ifstream ifs;
    ifs.open(FILENAME, ios::in);
    int id;
    string name;
    int deptid;
    
    int index = 0;
    while(ifs >> id && ifs >> name && ifs >> deptid)
    {
        Worker *worker = NULL;
        if (deptid == 1)
        {
            worker = new Employee(id, name, deptid);
        }
        else if (deptid == 2)
        {
            worker = new Manager(id, name, deptid);
        }
        else if (deptid == 3)
        {
            worker = new Boss(id, name, deptid);
        }
        this->m_EmpArray[index] = worker;
        index++;
    }
    ifs.close();
}

 显示所有职工信息:

void WorkerManager::show_Emp()
{
    if(this->is_Empty)
    {
        cout << "文件不存在或记录为空" << endl;
    }
    else
    {
        for(int i=0; i<this->m_EmpNum; i++)
        {
            this->m_EmpArray[i]->showInfor();
        }
    }
    system("pause");
    system("cls");
}

第八步:选择为3时删除职工

在workerManager.h中加入声明:

    void delete_Emp();
    int is_exist(int id);

先判断该职工是否存在,存在则返回下标,不存在返回-1:

// 判断职工是否存在,不存在返回-1
int WorkerManager::is_exist(int id)
{
    int index = -1;
    for (int i=0; i<this->m_EmpNum; i++)
    {
        if(this->m_EmpArray[i]->m_id == id)
        {
            index = i;
            break;
        }
    }
    return index;
}

再删除该职工信息:

void WorkerManager::delete_Emp()
{
    if(this->is_Empty)
    {
        cout << "文件不存在或记录为空" << endl;
    }
    else
    {
        cout << "请输入需要删除的职工的ID:" << endl;
        int id;
        cin >> id;
        int index = this->is_exist(id);
        if(index != -1)
        {
            for(int i=index; i<this->m_EmpNum-1; i++)
            {
                this->m_EmpArray[i] = this->m_EmpArray[i+1];
            }
            this->m_EmpNum--;
            // 将文件中数据同步更新
            this->save();
            cout << "删除成功" << endl;
        }
        else
        {
            cout << "删除失败,该职工不存在" << endl;
        }
    }
    system("pause");
    system("cls");
}

第九步:选择为4时修改信息

在workerManager.h中加入声明:

void change_Emp();

在workerManager.cpp中加入具体实现,先判断传入的这个人的id是否存在,再根据新建数据的格式修改信息:

void  WorkerManager::change_Emp()
{
    if(this->is_Empty)
    {
        cout << "文件不存在或记录为空" << endl;
    }
    else
    {
        cout << "请输入需要修改信息的职工的ID:" << endl;
        int id;
        cin >> id;
        int index = this->is_exist(id);
        if(index != -1)
        {
            cout << "查到系统中第" << index+1 << "号职工" << endl;
            delete this->m_EmpArray[index];
            int id;
            string name;
            int deptid;
            cout << "请输入新的职工编号:" << endl;
            cin >> id;
            cout << "请输入新的职工姓名:" << endl;
            cin >> name;
            cout << "请输入新的职位编号:" << endl;
            cin >> deptid;

            Worker *worker = NULL;
            switch(deptid)
            {
                case 1:
                    worker = new Employee(id, name, 1);
                    break;
                case 2:
                    worker = new Manager(id, name, 2);
                    break;
                case 3:
                    worker = new Boss(id, name, 3);
                    break;
                default:
                    break;
            }

            // !将创建的职工指针,保存到数组中
            this->m_EmpArray[index] = worker;

            cout << "修改成功" << endl;
            this->save(); 
        }
        else
        {
            cout << "修改失败,该职工不存在" << endl;
        }
    }
    system("pause");
    system("cls");
}

第十步:选择为5时查找员工

在workerManager.h中加入声明:

    void Find_Emp();

在workerManager.cpp中加入具体实现(两种查找方式,第一种按编号查找,先判断此人是否存在,存在的返回数组指针的下标;第二种按姓名查找,遍历指针数组对应的m_name):

void WorkerManager::Find_Emp()
{
    if(this->is_Empty)
    {
        cout << "文件不存在或记录为空" << endl;
    }
    else
    {
        cout << "请输入查找方式(1-按编号查找,2-按姓名查找):" << endl;
        int select = 0;
        cin >> select;

        if(select == 1)
        {
            cout << "请输入需要查找的职工的ID:" << endl;
            int id;
            cin >> id;
            int index = this->is_exist(id);
            if(index != -1)
            {
                cout << "查找成功,该职工信息如下:" << endl;
                this->m_EmpArray[index]->showInfor();
            }
            else
            {
                cout << "查找失败,该职工不存在" << endl;
            }
        }
        else if(select == 2)
        {
            cout << "请输入需要查找的职工的姓名:" << endl;
            bool tag = false;
            string name;
            cin >> name;
            for(int i=0; i<this->m_EmpNum; i++)
            {
                if(this->m_EmpArray[i]->m_name == name)
                {
                    tag = true;
                    cout << "查找成功,该职工信息如下:" << endl;
                    this->m_EmpArray[i]->showInfor();
                }
            }
            if(tag == false)
            {
                cout << "查找失败,该职工不存在" << endl;
            }
        }
        else
        {
            cout << "输入错误" << endl;
        }
    }
    system("pause");
    system("cls");
}

第11步:选择为6时排序

在workerManager.h中加入声明:

    void sort_Emp();

在workerManager.cpp中加入具体实现,有两种排序方式,按照职工编号升序或降序。用双重循环找到最小的职工对应的m_id,同时按照升序/降序排列。外层循环是确定最大值/最小值所放的位置,内层循环是寻找未排序数组中的最小值

void WorkerManager::sort_Emp()
{
    if(this->is_Empty)
    {
        cout << "文件不存在或记录为空" << endl;
        system("pause");
        system("cls");
    }
    else
    {
        cout << "请选择排序方式(1-按照职工编号升序排列,2-按照职工编号降序排列):" << endl;
        int select = 0;
        cin >> select;
        for(int i=0; i<this->m_EmpNum; i++)
        {
            int minOrMax = i;
            for(int j=i+1; j<this->m_EmpNum; j++)
            {
                if(select == 1) // 升序
                {
                    if(this->m_EmpArray[minOrMax]->m_id > this->m_EmpArray[j]->m_id)
                    {
                        minOrMax = j;
                    }
                }
                else // 降序
                {
                    if(this->m_EmpArray[minOrMax]->m_id < this->m_EmpArray[j]->m_id)
                    {
                        minOrMax = j;
                    }
                }
            }
            if(i != minOrMax)
            {
                Worker *temp = this->m_EmpArray[i];
                this->m_EmpArray[i] = this->m_EmpArray[minOrMax];
                this->m_EmpArray[minOrMax] = temp;
            } 
        }
        cout << "排序成果,排序后结果为:" << endl;
        this->save();
        this->show_Emp();
    }
}

第12步:选择为7时清除信息

在workerManager.h中加入声明:

    void deleteall();

在workerManager.cpp中加入具体实现,在删除之前先进行确认:

void WorkerManager::deleteall()
{
    cout << "确认清空? (1-yes,2-no)" << endl;
    int select = 0;
    cin >> select;
    if(select == 1)
    {
        ofstream ofs;
        ofs.open(FILENAME, ios::trunc);  // 删除文件后重新创建
        ofs.close();

        // 删除堆区的每个职工对象和数组指针
        if(this->m_EmpArray != NULL)
        {
            for(int i=0; i<this->m_EmpNum; i++)
            {
                if(this->m_EmpArray[i] != NULL)
                {
                    delete this->m_EmpArray[i];
                }
            }

            delete[] this->m_EmpArray;
            this->m_EmpArray = NULL;
            this->m_EmpNum = 0;
            this->is_Empty = true;

            cout << "清空完毕" << endl;
        }

    }
    system("pause");
    system("cls");
}

根据这里的实现,进一步修改WorkerManager的析构函数:

WorkerManager::~WorkerManager()
{
    if(this->m_EmpArray != NULL)
    {
        for(int i=0; i<this->m_EmpNum; i++)
        {
            if(this->m_EmpArray[i] != NULL)
            {
                delete this->m_EmpArray[i];
            }
        }

        delete[] this->m_EmpArray;
        this->m_EmpArray = NULL;
    }
}

最后:主函数设置分支结构

int main()
{
    // 实例化管理者对象
    WorkerManager wm;
    int choice = 0;
    while(true)
    {
        wm.show_Menu();
        cout << "请输入您的选择:" << endl;
        cin >> choice;
        switch(choice)
        {
            case 0: // 退出系统
                wm.ExitSystem();
                break;
            case 1:  // 增加职工
                wm.Add_Emp();
                break;
            case 2:  // 显示职工
                wm.show_Emp();
                break;
            case 3:  // 删除职工
                wm.delete_Emp();
                break;
            case 4:  // 修改职工
                wm.change_Emp();
                break;
            case 5: // 查找职工
                wm.Find_Emp();
                break;
            case 6:  // 排序职工
                wm.sort_Emp();
                break;
            case 7:  // 清空职工
                wm.deleteall();
                break;    
            default:
                system("cls"); // 清屏
                break;
        }
    }

    system("pause");
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值