实验目的与要求
设计一个利用文件处理方式实现电话号码簿的程序，具有增加数据、更新数据、查询数
据、删除数据以及重组文件的功能，删除数据在记录中作删除标志，重组文件指在物理上删
除作有删除标志的记录。
2、实验分析
电话号码簿要求设计实现的基本功能包括增加数据、更新数据、查询数据、删除数据以
及重组文件，这些功能都由函数来实现。通过菜单选择调用函数来实现相应的功能，这样条
理清晰，整体效果好，便于程序的调试。
定义电话结构体,包含姓名、电话号码等 4 个数据项。
struct TelephoneType
{ //电话结构
bool delTag; //删除标志
unsigned int seat; //序号
char name[16]; //姓名
char teleNo[18]; //电话号码
};
设计电话号码簿类,声明如下:
//电话号码簿类的声明
class TelephoneBook
{
private:
//数据成员
fstream file; //电话号码簿文件
//辅助函数
void AddData(); //添加数据
void UpdateData(); //更新数据
void SearchData();//查询数据
void DeleteData();
void Pack();
控制学院《高级程序设计与实践》实验教学指导书
34
public:
//构造函数，析构函数与方法
TelephoneBook();
virtual ~TelephoneBook(){ file.close();}
void Run();
};
在构造函数中,应以读写二进制方式打开数据文件。
当不存在文件 telph.dat 时,本应自动建立一个空文件,但实际运行时,有的 C++编译器
不会建立新文件,这应是 C++实现的一个 Bug,为此首先判断是否存在文件 telph.dat,当不存
在时,先创建一个空文件,这样实现代码更长,但程序更健壮。
TelephoneBook::TelephoneBook() // 无参构造函数
{
ifstream iFile("telph.dat"); // 建立输入文件
if (iFile.fail())
{ // 打开文件失败,表示不存在文件
ofstream oFile("telph.dat"); // 建立输出文件
if (oFile.fail()) throw("打开文件失败!"); // 抛出异常
oFile.close(); // 关闭文件
}
else
{ // 存在文件
iFile.close(); // 关闭文件
}
file.open("telph.dat", ios::in|ios::out|ios::binary); // 以读写方式打开文件
if (file.fail()) throw("打开文件失败!"); // 抛出异常
}
设计函数 void DeleteData()删除文件中的作废信息,在该函数中,数据的删除只是做删
除标记,数据信息仍然存放在文件中,而不是彻底删除,具体实现如下:
void TelephoneBook::DeleteData() // 删除数据, 只作删除标志
{
控制学院《高级程序设计与实践》实验教学指导书
35
TelephoneType telph; // 电话号码结构
unsigned int seat; // 序号
cout << "输入要删除电话的序号:";
cin >> seat; // 输入序号
file.seekg(0); // 定位
file.read((char *)&telph, sizeof(TelephoneType)); // 读记录
while (!file.eof())
{ // 文件末结束
if (telph.seat == seat // 序号相同
&& !telph.delTag // 记录正常, 未作删除标志
) break; // 查询成功
file.read((char *)&telph, sizeof(TelephoneType)); // 读记录
}
if (!file.eof())
{ // 查询成功
cout << "被删除记录为:" << endl;
cout << setw(18) << telph.seat << setw(18) << telph.name <<
setw(18) << telph.teleNo << endl;
// 输出记录
telph.delTag = true; // 删除标志
file.seekg(-sizeof(TelephoneType), ios::cur); // 定位
file.write((char *)&telph, sizeof(TelephoneType)); // 写入记录
cout << "删除成功!" << endl;
}
else
{ // 查询失败
cout << "删除失败!" << endl;
file.clear(); // 清除文件结束标志
}
}
函数 Pack（）在物理上删除做有删除标记的记录，这样更节约空间，示例如下：
控制学院《高级程序设计与实践》实验教学指导书
36
void TelephoneBook::Pack() // 在物理上删除作有删除标记的记录
{
ofstream outFile("tem.dat", ios::app | ios::binary); // 建立输出文件对象
TelephoneType telph; // 电话号码结构
file.seekg(0); // 定位
file.read((char *)&telph, sizeof(TelephoneType)); // 读记录
while (!file.eof())
{ // 文件末结束
if (!telph.delTag)
{ // 记录正常, 未作删除标志
outFile.write((char *)&telph, sizeof(TelephoneType));// 写记录
}
file.read((char *)&telph, sizeof(TelephoneType)); // 继续读记录
}
file.close(); // 关闭文件
outFile.close(); // 关闭文件
remove("telph.dat"); // 删除文件
rename("tem.dat", "telph.dat"); // 更改文件名
file.open("telph.dat", ios::in|ios::out|ios::binary); // 重新打开文件
}
方法 Run()以菜单方式实现增加数据、更新数据、查询数据、删除数据以及重组文件的
功能,具体实现如下:
void TelephoneBook::Run() // 处理电话号码簿
{
int select; // 选择菜单号
do
{
cout << "请选择:" << endl;
cout << "1. 增加数据" << endl;
cout << "2. 更新数据" << endl;
控制学院《高级程序设计与实践》实验教学指导书
37
cout << "3. 查询数据" << endl;
cout << "4. 删除数据" << endl;
cout << "5. 重组文件" << endl;
cout << "6. 退出" << endl;
cin >> select; // 输入选择
while (cin.get() != '\n'); // 跳过当前行后面的字符
switch (select)
{
case 1:
AddData(); // 增加数据
break;
case 2:
UpdateData(); // 更新数据
break;
case 3:
SearchData(); // 查询数据
break;
case 4:
DeleteData(); // 删除数据
break;
case 5:
Pack(); // 在物理上删除作有删除标记的记录
break;
}
}
while (select != 6); // 选择 6 将退出
}
请大家实现其他函数，完成完整的实验程序。