记录使用c++编写机房预约系统的问题和一些技巧
1、查看文件是否为空文件
fstream read_file;
read_file.open(filename,ios::in);
char c;
read_file>>c;
//如果文件为空,返回
if (read_file.eof())
{
return 0;
}else{
//不为空,把读出来的字符放回去。进行其他操作
read_file.putback(c);
}
2、根据空格切割txt文件,存储到vector数组中
方法一:先判断文件是否为空,不为空进行后续操作。使用全局函数getline逐行读取文件内容,存储到temp_data中,再逐行打印。
fstream read_file;
read_file.open(filename,ios::in);
if(!read_file.is_open()){
return 0;
}
//先要判断文件是否为空!!!
char c;
read_file>>c;
if (read_file.eof())
{
return 0;
}else{
read_file.putback(c);
//逐行对应,空格分割.位置是int类型的
string temp_data;
//创建一个数组,来存储切割后的字符串
while(getline(read_file,temp_data)){
//直接找用户名会出现重复的失误的情况,应该先切割,再判断是否相同
int size=temp_data.size();
int pos=0;
vector<string> substr;
for(int i=0;i<size;i++){
pos=temp_data.find(" ",i); //在i的位置后面按空格找
if(pos!=-1){
substr.push_back(temp_data.substr(i,pos-i));
}else{ //没有空格直接取最后一串字字符串
substr.push_back(temp_data.substr(i,size));
break;
}
i=i+temp_data.substr(i,pos-i).size();
}
//输出
cout<<numbername<<" :"<<substr.at(0)<<" 姓名: "<<substr.at(1)<<" 密码: "<<substr.at(2)<<endl;
}
}
read_file.close();
方法二:直接利用读取时候,碰到空格停止的特性分割
while(read_file>>a&&read_file>>b&&read_file>>c&&read_file>>d&&read_file>>e){
cout<<"预约人 :"<<a<<" 预约日期: "<<b<<" 预约时段: "<<c<<
" 预约机房: "<<d<<" 预约状态: "<<e<<endl;
}
3、修改文件内容
方法一:由于文件流不能边读边写,因此使用了临时的txt文件存储修改后的内容. 使用该代码之后还需要覆盖原文件才能达到效果。
//删除了部分代码
//根据名字找记录,count用来计数,等于num时就对了。直接在getline里修改。
int count=0;
string filename=FILENAME;
filename+="order.txt";
string temp_file=FILENAME;
temp_file+="temp_order.txt";
fstream read_file;
fstream out_file;
//不加上in就没办法读到文件
read_file.open(filename,ios::in);
//临时文件
out_file.open(temp_file,ios::out);
if (!read_file.is_open())
{
cout<<"文件打开失败或不存在!"<<endl;
system("pause");
return;
}
//逐行对应,空格分割.位置是int类型的
string temp_data;
//创建一个数组,来存储切割后的字符串
while(getline(read_file,temp_data)){
//直接找用户名会出现重复的失误的情况,应该先切割,再判断是否相同
int size=temp_data.size();
int pos=0;
vector<string> substr;
for(int i=0;i<size;i++){
pos=temp_data.find(" ",i); //在i的位置后面按空格找
if(pos!=-1){
substr.push_back(temp_data.substr(i,pos-i));
}else{ //没有空格直接取最后一串
substr.push_back(temp_data.substr(i,size));
break;
}
i=i+temp_data.substr(i,pos-i).size();
}
if(substr.at(0)==name){
count++;
if (count==num)
{ //写入修改后的内容
out_file<<substr.at(0);out_file<<" ";out_file<<substr.at(1);out_file<<" ";
out_file<<substr.at(2);out_file<<" ";out_file<<substr.at(3);out_file<<" ";
out_file<<check_statu;
char c;
read_file>>c;
if (!read_file.eof())
{
out_file<<endl;
}
read_file.putback(c);
}else{
//直接整条复制进去
out_file<<temp_data;
char c;
read_file>>c;
if (!read_file.eof())
{
out_file<<endl;
}
read_file.putback(c);
}
}
}
read_file.close();
out_file.close();
return;
}
方法二:
在最开始的时候维护一个预约类,初始化该类的时候就读取记录预约的文件。修改的时候修改该状态再保存。保存就是用 out | trunc的方式,重建文件,再写入维护的数据。
4、对比自己的系统和标准系统的启发
2、读取文件
在txt文件中,可以直接用&&符号得到空格分割的子字符串。
例如while(ifs>>a &&ifs>>b &&ifs>>c)
3、在登录的时候,就new了一个对应身份的管理员/教师/学生,后期可以作为参数被传递使用。
传递的时候传的是指针: Identity * & manager 。
可以强制把父类指针转为子类指针,才能调用子类的其他接口: Manager *man= (Manager *) manager.
4、在cpp缺少其他头文件时,可以在它对应的h头文件中包含其他头文件。
5、注销登录之后应该返回最初的登录界面
(return就结束这个函数,回到上一级了;而break只是退出当前的while循环;exit(0)是结束整个程序)
6、在自己编写的有参构造函数中,可以调用一些初始化函数,例如可以加载文件中的一些信息。
(在每次更新文件的时候,都要重新读入文件内容/即重新初始化)
7、在6的基础上,因为在初始化函数中加载了文件的信息,所以可以存储到vector数组中,所以之后显示账号的时候就很方便,直接for_each遍历数组即可。
8、善用嵌套容器。
比如对于预约的属性,可以使用map来进行存储,即键值对的方式。而一条记录则对应多个map格式的数据,可以在其外层嵌套一个map容器来存储(map
9、注意substr函数的使用
a.substr(开始截取的位置,要截取的字符数)
10、更新预约的实现
因为在最开始的时候,系统维护了一个记录所有预约的map嵌套容器,所以当修改的时候,会修改该容器的内容,再调用更新接口保存文件即可。利用的是输出流的 out | trunc 模式,即先清空文件再写入新的文件流。这就是实时维护一个数据数组的好处!!!
11、string转化为int
先转化为c语言风格的const char *,再用atoi函数转化。即 atoi(x.c_str())