整个系统用到的C++语法有:
1.C++高级文件输入输出(包括文件的常用打开模式)
2.C++数据类型time_t
3.C++结构体
程序中遇到的一些问题及解决:
1.string类对象的赋值。
比如string x=“sdfsf”+数字型变量;
这样显然是不可取的,此时就需要用到string类对象的数字转换函数to_string(T value)来将T类型的数字值转换为字符串形式(详见精通C++820页)
2.time_t数据类型的使用见678页
3.在进行删除操作时,遇到从把一个文件的内容写入另一个文件时总会在eof()判断结束后又执行一次while循环的问题,这是因为当时吧eof()函数的判断写到了while()表达式中所造成的的(详见程序),
判断一个文件结束标志(即eof()函数)的合理使用参考博客:https://blog.csdn.net/ungoneless/article/details/51280072
代码如下:
#include<iostream>
#include<fstream>
#include<string>
#include<iomanip>
#include<cctype>//toupper()函数
#include<ctime>//设置时间
using namespace std;
void showClient();//显示所有账户
void addNewClient();//新增账户
void showMenu();//显示菜单
void deleteClient();//删除账户
void changeClient();//更改某账户信息
void lookupClient();//查看某账户信息
const int NAME_SIZE = 15, ADDR_SIZE = 50, POSTAL_SIZE = 10, CITY_SIZE = 20, DATE_SIZE = 50;//账户各数组大小
struct clientAccount
{//客户账户
char name[NAME_SIZE];
char address[ADDR_SIZE];
char city[CITY_SIZE];
char postalcode[POSTAL_SIZE];
int balance;
char date[DATE_SIZE];
};
time_t epSeconds;//C++数据类型time_t表示自时间原点(1900年1月1日)以来所经过的秒数
int main()
{
//showMenu();//如果只显示1次菜单,do循环中的showMenu()移出即可
do
{
showMenu();
int choice;//业务代号
cout << "请选择相应序号进行业务处理! ";
cin >> choice;
cin.ignore();//清除以回车结束的输入缓冲区的内容,消除上一次输入对下一次输入的影响
cout << endl;
switch (choice)
{//业务代号进入不同业务处理
case 1:
addNewClient();
break;
case 2:
showClient();
break;
case 3:
deleteClient();
break;
case 4:
changeClient();
break;
case 5:
lookupClient();
break;
case 6:exit(0);
}
cout << endl;
} while (1);
return 0;
}
void showMenu()
{
//菜单显示格式
cout << fixed << showpoint << setprecision(2);
cout << "-----------------客户账户管理系统----------------" << endl;
cout <<setw(22)<< "1.创建客户账户记录";
cout <<setw(25)<< "2.显示全部客户账户记录" << endl;
cout <<setw(22)<< "3.删除客户账户记录";
cout <<setw(21)<< "4.更改客户账户记录" << endl;
cout << setw(22)<<"5.查找客户账户记录";
cout <<setw(13)<< "6.退出程序" << endl;
cout << endl;
}
void addNewClient()
{
fstream input("clientAccountSystem.dat", ios::in | ios::binary);//判断是否存在文件clientAccountSystem.dat
if (!input)
{
fstream output;
output.open("clientAccountSystem.dat", ios::out | ios::binary);//同时使用ios::in和ios::out文件的当前内容将被保留,且读写位置最初在文件的开头
if (!output)
{//判断文件是否打开
cout << "文件未打开!" << endl;
exit(0);
}
output.close();
}
else { input.close(); }
epSeconds = time(0);//自时间原点(计算机科学设定日历时间标记时间原点为1970年1月1日午夜)到现在的秒数
tm *pCalendarTime = new tm;
//cout << epSeconds;
localtime_s(pCalendarTime, &epSeconds);
fstream output;
output.open("clientAccountSystem.dat",ios::in|ios::out | ios::binary);//同时使用ios::in和ios::out文件的当前内容将被保留,且读写位置最初在文件的开头
if (!output)
{//判断文件是否打开
cout << "文件未打开!" << endl;
exit(0);
}
bool add = 0;//是否继续新增客户账户
clientAccount client;//客户账户
string inputString;//输入字符串
output.seekp(0,ios::end);//将文件写入位置调整到文件末尾(如果不进行位置调整,由于是以ios::in|ios::out方式打开,文件始终在最开始的位置,会使新增的用户覆盖原有用户)
do
{
cout << "请输入客户姓名:";
getline(cin, inputString);
strcpy_s(client.name, inputString.c_str());//完全可以换种方式输入,书上这样写的就照搬过来了
cout << "请输入客户地址:";
getline(cin, inputString);
strcpy_s(client.address, inputString.c_str());
cout << "请输入所在城市:";
getline(cin, inputString);
strcpy_s(client.city, inputString.c_str());
cout << "请输入充值金额:";
cin >> client.balance;
cin.ignore();
cout << "请输入邮政编码:";
getline(cin, inputString);
strcpy_s(client.postalcode, inputString.c_str());
inputString = "添加于";
inputString +=to_string(1900+pCalendarTime->tm_year)+"年" + to_string(pCalendarTime->tm_mon) + "月" + to_string(pCalendarTime->tm_mday) + "日" + to_string(pCalendarTime->tm_hour) + "时" + to_string(pCalendarTime->tm_min) + "分" + to_string(pCalendarTime->tm_sec) + "秒";
strcpy_s(client.date, inputString.c_str());
output.write(reinterpret_cast<char*>(&client), sizeof(client));//写入文件操作
cout << "\n是否继续添加客户?| 1.继续请输入1 | 2.不继续请输入0 |";
cin >> add;
cin.ignore();
} while (add == 1);
output.close();//关闭文件
}
//同类型不再注释,参照上面的代码注释
//查找某客户账户信息
void lookupClient()
{
char name[NAME_SIZE];
clientAccount client;
int i = 0;//用来移动读操作的位置
int count = 0;//用来判断客户是否存在
cout << "请输入客户姓名:";
cin >> name;
cin.ignore();
fstream lookup("clientAccountSystem.dat", ios::in | ios::out | ios::binary);
if (!lookup)
{
cout << "文件未打开!" << endl;
exit(0);
}
while (!lookup.eof())
{
lookup.seekg(sizeof(clientAccount)*i++, ios::beg);//移动读操作位置
lookup.read(reinterpret_cast<char *>(&client), sizeof(client));//读取该位置客户账户
if (!strcmp(name, client.name))
{
//如果有和输入账户名相同账户,则count加1,表示客户账户存在
count++;
//输出客户账户信息
cout << "客户姓名:" << client.name << endl;
cout << "客户当前余额:" << client.balance << endl;
cout << "客户地址:" << client.address << endl;
cout << "客户所在城市:" << client.city << endl;
cout << "邮政编码:" << client.postalcode << endl;
cout << client.date << endl;
}
}
char response = 'N';//判断是否创建账户
string inputString;
if (count == 0)
{
cout << "客户账户不存在!" << endl;
cout << "是否创建账户?| 是请输入'Y' | 否请输入'N' |";
cin >> response;
cin.ignore();
if (toupper(response) == 'Y')
{
fstream output;
output.open("clientAccountSystem.dat", ios::out|ios::in | ios::binary);
if (!output)
{
cout << "文件未打开!" << endl;
exit(0);
}
epSeconds = time(0);//自时间原点(计算机科学设定日历时间标记时间原点为1970年1月1日午夜)到现在的秒数
tm *pCalendarTime = new tm;
//cout << epSeconds;
localtime_s(pCalendarTime, &epSeconds);
clientAccount client;
string inputString;
output.seekp(0, ios::end);
strcpy_s(client.name, name);
cout << "请输入客户地址:";
getline(cin, inputString);
strcpy_s(client.address, inputString.c_str());
cout << "请输入所在城市:";
getline(cin, inputString);
strcpy_s(client.city, inputString.c_str());
cout << "请输入充值金额:";
cin >> client.balance;
cin.ignore();
cout << "请输入邮政编码:";
getline(cin, inputString);
strcpy_s(client.postalcode, inputString.c_str());
inputString = "添加于";
inputString += to_string(1900 + pCalendarTime->tm_year) + "年" + to_string(pCalendarTime->tm_mon) + "月" + to_string(pCalendarTime->tm_mday) + "日" + to_string(pCalendarTime->tm_hour) + "时" + to_string(pCalendarTime->tm_min) + "分" + to_string(pCalendarTime->tm_sec) + "秒";
strcpy_s(client.date, inputString.c_str());
output.write(reinterpret_cast<char*>(&client), sizeof(client));
output.close();
}
}
lookup.close();
}
//删除账户
void deleteClient()
{
char confirm = 'N';//确认删除
clientAccount client;
fstream clear("clientAccountSystem.dat", ios::in | ios::out | ios::binary);
if (!clear)
{
cout << "文件未打开!" << endl;
exit(0);
}
showClient();//显示所有账户,以供选择待删除账户代号
int number;
cout << "请输入待删除客户编号:";
cin >> number;
cin.ignore();
//找到待删除账户的位置
clear.seekg(sizeof(clientAccount)*(number-1), ios::beg);
clear.read(reinterpret_cast<char*>(&client), sizeof(client));
//确认删除客户账户
cout << "客户姓名:" << client.name << endl;
cout << "客户当前余额:" << client.balance << endl;
cout << "客户地址:" << client.address << endl;
cout << "客户所在城市:" << client.city << endl;
cout << "邮政编码:" << client.postalcode << endl;
cout << client.date << endl;
cout << "请确认是否删除当前账户?| 确认删除请输入'Y' | 不删除请输入'N' |";
cin >> confirm;
cin.ignore();
if (toupper(confirm) == 'Y')
{//若确认删除,则将未删除部分写入另一个文件(即跳过待删除的账户)
fstream output;
output.open("clientAccountSystem1.dat", ios::out | ios::binary);
if (!output)
{
cout << "文件未打开!";
exit(0);
}
int i = 0,//用i的增加进行移动以匹配输入的删除选择代号,
j=0;//如果找到了要删除的账户时,不增加j,已和写入位置匹配
while (1)
{
clear.seekg(sizeof(clientAccount)*i, ios::beg);
clear.read(reinterpret_cast<char *>(&client), sizeof(client));
if (clear.eof()) break;//先判断是否到了原文件结束标志处,必须这样写,否则循环会多进行一次而将程序的最后一个账户重复存储一次
if (i ==(number-1) )
{
i++;
}
else
{//写入新文件
clear.seekp(sizeof(clientAccount)*j, ios::beg);
output.write(reinterpret_cast<char *>(&client), sizeof(client));
i++;
j++;
}
}
output.close();
}
clear.close();
if (confirm == 'Y')
{
remove("clientAccountSystem.dat");//删除源文件
rename("clientAccountSystem1.dat", "clientAccountSystem.dat");//重命名新文件为源文件名
}
}
//更新账户信息
void changeClient()
{
int number;
clientAccount client;
fstream change("clientAccountSystem.dat", ios::in | ios::out | ios::binary);
showClient();
cout << "请输入要更正的客户账户编号:";
cin >> number;
cin.ignore();
change.seekg(sizeof(clientAccount)*(number - 1), ios::beg);
change.read(reinterpret_cast<char*>(&client), sizeof(client));
int choice;//更新信息编号
char response = 'N';
string input;
do
{
cout << "请选择要更正的内容编号:|1.姓名|2.地址|3.城市|4.余额|5.邮政编码| ";
cin >> choice;
cin.ignore();
switch (choice)
{
case 1:cout << "请输入:"; getline(cin, input); strcpy_s(client.name, input.c_str()); break;
case 2:cout << "请输入:"; cin >> client.address; cin.ignore(); break;
case 3:cout << "请输入:"; cin >> client.city; cin.ignore(); break;
case 4:cout << "请输入:"; cin >> client.balance; cin.ignore(); break;
case 5:cout << "请输入:"; cin >> client.postalcode; cin.ignore(); break;
}
cout << "是否继续更正当前账户?| 是请输入'Y' | 否请输入'N' |";
cin >> response;
cin.ignore();
}while (toupper(response) == 'Y');
//更新后账户数据写入文件
epSeconds = time(0);//自时间原点(计算机科学设定日历时间标记时间原点为1970年1月1日午夜)到现在的秒数
tm *pCalendarTime = new tm;
//cout << epSeconds;
localtime_s(pCalendarTime, &epSeconds);
string inputString = "更新于";
inputString += to_string(1900 + pCalendarTime->tm_year) + "年" + to_string(pCalendarTime->tm_mon) + "月" + to_string(pCalendarTime->tm_mday) + "日" + to_string(pCalendarTime->tm_hour) + "时" + to_string(pCalendarTime->tm_min) + "分" + to_string(pCalendarTime->tm_sec) + "秒";
strcpy_s(client.date, inputString.c_str());
change.seekp(sizeof(clientAccount)*(number - 1), ios::beg);
change.write(reinterpret_cast<char *>(&client), sizeof(client));
change.close();
}
//所有客户账户数据陈列
void showClient()
{
int i = 1;
fstream input("clientAccountSystem.dat", ios::in | ios::binary);
if (!input)
{
cout << "文件读入失败!";
exit(0);
}
clientAccount client;
input.read(reinterpret_cast<char*>(&client), sizeof(client));
while (!input.eof())
{
cout << i++ << ".";
cout << "客户姓名:" << client.name << endl;
cout << "客户当前余额:" << client.balance << endl;
cout << "客户地址:" << client.address << endl;
cout << "客户所在城市:" << client.city << endl;
cout << "邮政编码:" << client.postalcode << endl;
cout << client.date << endl << endl;
input.read(reinterpret_cast<char*>(&client), sizeof(client));
}
input.close();
}
参考文献:精通C++第9版,Tony Gaddis(黄刚等译)