1、写文件
①在workerManager.h中添加宏常量,并且包含头文件 fstream
②成员函数声明
在workerManager.h中类里添加成员函数 void save()
③保存文件功能实现
ios::out
模式会:
-
如果文件存在,则打开文件并清空其内容(即文件内容会被覆盖)。
-
如果文件不存在,则创建一个新文件。
workerManager.cpp实现:
职工管理系统.cpp:调用成员函数,测试成功:
后续修改、删除等操作后,都需要再次调用save()函数。
2、读文件
每次开始运行程序,将文件中数据读取到程序中,在构造函数中实现。分情况:
为了避免在程序多个地方重复检查文件状态,可以通过标志清晰地表达:在workerManager.h中添加新的成员属性:bool m_FileIsEmpty,标志文件是否为空。
①文件不存在
is_open()
的注意事项:
a.文件路径:确保文件路径正确。相对路径是相对于程序运行时的当前工作目录,绝对路径Windows 中使用 \\
,Linux 中使用 /。
b.文件权限:
确保程序有权限访问文件。例如,在 Linux 中,如果文件权限为 rw-r--r--
,则会返回 false
。
c.文件流状态:is_open()
只检查文件是否成功打开,不检查文件是否为空或是否有有效数据。
删除文件后,测试初始化数据功能,成功。
②文件存在且数据为空
在workerManager.cpp中的构造函数追加代码:
a.为什么要先读取一个字符?
当你尝试使⽤"ifs >> ch"或 "ifs.get(ch)"读取⼀个字符时, 由于⽂件为空, 读取操作会失败,⽂件流会⽴即触发"EOF 状态", ch没有被成功读取,值保持不变, 可能是未定义的或初始值。
而直接调⽤“ifs.eof()”会返回 false, 因为⽂件指针还没有尝试读取任何内容, 程序并不知道是否已经到达⽂件末尾。
ifs >> ch
会跳过空白字符(如空格、换行符等),可能会造成误判。
b.文件指针
当你打开一个文件时,文件指针默认位于文件的开头(即位置 0
)。
ifs >> ch
读取成功,文件指针会移动到下一个字符的位置。读取失败,文件指针不会移动。
可以使用 tellg()
来获取当前文件指针的位置:
测试:
c.一些新方法
1)peek()
是 ifstream
的一个成员函数,用于查看文件中的下一个字符,但不会移动文件指针。如果文件为空,peek()
会返回 EOF
。同样,它会跳过空白字符(如空格、换行符等),可能导致误判。
2)seekg
和 tellg
是 ifstream
的成员函数,通过将文件指针移动到文件末尾并检查文件大小,可以准确判断文件是否为空。文件大小计算包括换行符和文件结束符。
将文件创建后清空文件内容,测试初始化功能,成功。
③文件存在且保存职工数据
在C++中,动态数组的内存分配是一次性完成的,需要在创建数组时指定其大小。如果尝试在不知道大小的情况下逐个添加对象,可能会导致内存分配失败或内存浪费。
a.获取记录的职工人数,开辟空间
在workerManager.h中添加成员函数 int get_EmpNum();
workerManager.cpp实现:
WorkerManager.cpp添加代码,手动添加一些职工数据,测试获取职工数量函数,成功。
b. 初始化数组
在WorkerManager.h中添加成员函数 void init_Emp();
workerManager.cpp实现:
注意:在循环的末尾,不要添加:delete worker
:
-
m_EmpArray[index]
中的指针变成一个悬空指针虽仍然指向原来的内存地址,但指向的内存被释放,访问它会导致未定义行为(通常是程序崩溃或数据损坏)。 -
对象无法访问。
WorkerManager.cpp继续添加代码,测试成功。
3、清空文件
在workerManager.h中添加成员函数 void Clean_File();
workerManager.cpp实现:
职工管理系统.cpp:case7分支调用成员函数,测试成功。
a.ios::trunc
-
如果文件已经存在,会清空文件内容(即将文件大小截断为 0)。
-
如果文件不存在,会自动创建一个空文件。
b.delete[] m_EmpArray
-
如果数组元素是普通对象(非指针),
delete[] m_EmpArray
会:调用每个数组元素的析构函数,并释放整个数组的内存。不需要手动释放数组中的每个对象。 -
如果数组元素是指针,
delete[] m_EmpArray
只会:释放数组本身的内存(即指针数组的内存),不会释放指针指向的对象。需要手动释放数组中的每个对象,否则会导致内存泄漏。
c.析构函数怎么办呢?
手动调用Clean_File():显式的清理,析构函数:在对象销毁时自动调用。如过 Clean_File()
被调用过,m_EmpArray
已经被释放并置空,析构函数再次释放会导致重复释放。如果 Clean_File()
没有被调用,析构函数必须释放 m_EmpArray
,否则会导致内存泄漏。
为了避免重复释放,同时确保资源在任何情况下都能被正确释放,可以采用以下方法:
方法 1:使用标志位
在类中添加一个标志位(如 bool m_IsCleaned; // 标志位),用于记录 Clean_File()
是否被调用过。在析构函数中根据标志位决定是否释放资源。
方法 2:使用智能指针
使用 std::unique_ptr
或 std::shared_ptr
管理动态内存,避免手动释放内存的麻烦。
补充:nullptr
和 NULL
的区别:
碎碎念:
回家真幸福,每一位妇女都是最棒的!❤
背挺直一点,向前站一点,走好自己选择的路。