class="p0" style="text-align: center; margin-top: 0pt; margin-bottom: 0pt;">两次编写管理系统心得体会
大一下学期,我正式开始学习C++,为了巩固自己所学到的知识,我开始编写我学习计算机以来第一个综合性的实验项目:图书管理系统。
在编写图书管理系统时,几乎是从一无所知开始的,犯的错误,走的弯路数不胜数,在停停写写一个月后,图书管理系统终于编写出来:
这是效果图:
然而,这个系统是在我完全没有经验的情况下编写的,存在的缺陷,BUG自然数不胜数,然而,最大的缺陷之一就是他的文件操作效率非常之低;在导师的提点之下,我在七月初进行了学生成绩管理系统的开发,设计上,两个系统非常相似,学生成管理系统就连界面都是使用了在做图书管理系统时封装好的界面类,然而,两大系统最大的不同就在于在文件操作上的不同:
在此,我将对两个系统进行对比分析:
注:因为是实验项目,所以不涉及数据库的知识。(所涉及的信息量也很小)
NO.1?存和取:
如果把硬盘里的数据比作仓库里的物品,内存比作货架上的物品,那么我在编写图书管理系统的时候,“货架上”经常是空荡荡的,每次接受到“消费者”的指令,“我”都会把物品从仓库里取出来,每次“进货”,修改数据,都直接把他们塞进仓库。
请先看看以下两段代码:
这是user类(reader类和ruder类的基类)的方法,调取读者花名册。
?
void?user::manlist()
{
int?cpbook;
ifstream?fin("count\\mannumber.txt");//这样分两次打开,可避免读文件时,误改了源文件
fin>>cpbook;//从记事本读取书的数目
fin.close();
int?i;
ifstream?fin2("manstorage\\manlist.txt");
for(?i=0;i<cpbook;i++)
{
fin2>>name>>key>>number;
cout<<"姓名:"<<setfill('?')<<setw(10)<<name<<"??密码:"<<setfill('?')<<setw(10)<<key<<"??学号:"<<setfill('?')<<setw(10)<<number;
cout<<endl;
}
????fin2.close();
}
int??user::exactFind(int?i)
{?
int?ctrl=0;
string?nofound="呵呵,没有这个人哦~~";
string?c;
char?na[40];
cout<<"请输入用户名:";
cin>>na;
c.assign(na);
if(i==1||i==0)
{c=Address(c);}
if(i==2)
{c=Address5(c);}
????ifstream?fin3(c);
if(!fin3)
{
?cout<<nofound;
?ctrl=1;
?}
fin3>>name;
fin3>>key;
fin3>>number;
fin3.close();
if(i==0&&ctrl==0)
{
cout<<"姓名:"<<setfill('?')<<setw(10)<<name<<"??密码:"<<setfill('?')<<setw(10)<<key<<"??学号:"<<setfill('?')<<setw(10)<<number;
}
return?ctrl;
}
下面是添加一名新用户操作的源代码:
这是ruler里的一个方法(Rulerdefine.cpp),增加新读者。
void?Ruler::addMan(Reader?&?m)
{
ifstream?fin("count\\mannumber.txt");//这样分两次打开,可避免读文件时,误改了源文件
fin>>cpman;//从记事本会员的数目
fin.close();//关闭记事本
for(int?i=0;i<cpman;i++)
{
if(m==*man[i])
{
cout<<"already";
return;
}
}//检查新添加的会员是否已经存在(“==”号已经经过重载)
?
???man[cpman++]=&m;//若不存在则添加一名新成员
???????????ofstream?fout("Manstorage\\manlist.txt",?ios::app);
??fout<<m;
???fout.close();
???//文件操作,将改名新成员的信息存在manlist(名单)中
???string?c;
???c=m.getName();
???cout<<c;
???c=Address(c);//通过函数Address()将name拷贝并变成地址形式赋给c;
???ofstream?fout3(c,?ios::binary);
fout3<<m;
//(下一步将借书情况写在里边,下一步要录入vector中的信息啦)
???fout3.close();//每个成员的详细信息会存在一个独立的txt文件
?
?
???c=m.getName();
???c=Address3(c);//通过函数Address()将name拷贝并变成地址形式赋给c;
???ofstream?fout4(c,?ios::app);
???fout4.close();//每个成员的详细信息会存在一个独立的txt文件
?
?
????ofstream?fout2("count\\mannumber.txt",?ios::binary);
????fout2<<cpman;
fout2.close();//每添加一个成员计数文件mannumber就会+1
}
加粗的地方是文件操作的部分。我们可以看到,执行查找操作时,是从硬盘中调取数据,当方法调用结束之后,内存将会被回收,执行增加用户的操作时,首先调取一个存储用户数的文件读取已经登记在册的用户数量这个数据,之后将用户信息单独储存在一个文件,包括用户的基本信息和所借的书,然后再将用户的部分信息存在一个统一的文件里(很麻烦)。这样的操作相当繁琐,因为几乎是只要对用户信息一点点的修改都需要修改多个文件,这样是非常容易出错滴……
现在,我们来看看在学生成绩系统中,我们是怎样进行文件操作的:
void?main()
???{
???int?choose;//界面选择(选项)
???char?choose2;//界面选择(是否退出)
???winDesign?line;//画直线
???windowDesigner?window(line);//画方框
???Browse?Gradeone;//一年级
???Browse?Gradetwo;//二年级
???Browse?Teacher;//教师
???student?Student(window);
???teacher?Ateacher(window);
???gradeone?boy(window);//一年级新生
???gradetwo?boy2(window);
???int?Count1;//一年级人数计数器
???int?Count2;//二年级人数计数器
???int?CountTeacher;//教师人数计数器
???vector<Browse>?gradeOneList;//容器一年级
???vector<Browse>?gradeTwoList;//容器二年级
???vector<Browse>?TeacherList;//容器教师
??//读取老师数据
????ifstream?finteachercount("teacherlist\\count.txt");//从硬盘中读取信息
finteachercount>>CountTeacher;//读取人数信息
finteachercount.close();//关闭
???ifstream?finteacher("teacherlist\\listTeacher.txt");//读取学生详细信息
???for(int?i?=?0;i<CountTeacher;i++)//
???{
???finteacher>>Teacher;
???TeacherList.push_back(Teacher);//将信息放入容器
???}
???finteacher.close();//关闭
???//读取大一学生数据
???ifstream?fincountOne("gradeonestudent\\count.txt");//从硬盘中读取信息
???fincountOne>>Count1;//读取人数信息
???fincountOne.close();//关闭
???ifstream?finGradeone("gradeonestudent\\list1.txt");//读取学生详细信息
???for(int?i?=?0;i<Count1;i++)//
???{
???finGradeone>>Gradeone;
???gradeOneList.push_back(Gradeone);//将信息放入容器
???}
???finGradeone.close();//关闭
???//读取大二学生数据:
???ifstream?fincountTwo("gradetwostudent\\count.txt");//从硬盘中读取信息
???fincountTwo>>Count2;//读取人数信息
???fincountTwo.close();//关闭
???ifstream?finGradetwo("gradetwostudent\\list2.txt");//读取学生详细信息
???for(int?i?=?0;i<Count2;i++)//
???{
???finGradetwo>>Gradetwo;
???gradeTwoList.push_back(Gradetwo);//将信息放入容器
???}
???finGradetwo.close();//关闭
???//boy.showList(gradeOneList);
???//boy2.showList(gradeTwoList);
string?senmain0[4]={"学生成绩管理系统","1、学生登陆","2、教师登陆","3、退出"};//声明主页面内容
string?senexit[3]={"您确定要退出么","(Y)是","(任意健)否"};
do
{
window.mainwin(senmain0,4,4);
cout<<"您的选择是:";
cin>>choose;
switch(choose)
{
case?1:system("cls");Student.Login(window,Student,gradeOneList,gradeTwoList);break;
case?2:system("cls");Ateacher.Login(window,Student,gradeOneList,gradeTwoList,TeacherList);system("pause");break;
case?3:system("cls");
???window.questionwin(senexit,3,3);
???cin>>choose2;
???if(choose2=='Y'||choose2=='y')
???{?choose=7;};break;
default:
break;
}
system("cls");
}while(choose!=7);
//存储一年级同学的信息
//存储count1;
ofstream?foutGradeOneCount("gradeonestudent\\count.txt",ios::binary);
Count1=gradeOneList.size();
foutGradeOneCount<<Count1;
foutGradeOneCount.close();
//储存学生成绩
ofstream?foutGradeone("gradeonestudent\\list1.txt",ios::binary);
for(int?i?=?0;i<gradeOneList.size();i++)
{
foutGradeone<<gradeOneList[i];
}
foutGradeone.close();
//存储二年级同学的信息
//存储count2;
ofstream?foutGradeTwoCount("gradetwostudent\\count.txt",ios::binary);
Count2=gradeTwoList.size();
foutGradeTwoCount<<Count2;
foutGradeTwoCount.close();
//储存学生成绩
ofstream?foutGradetwo("gradetwostudent\\list2.txt",ios::binary);
for(int?i?=?0;i<gradeTwoList.size();i++)
{
foutGradetwo<<gradeTwoList[i];
}
foutGradetwo.close();
system("pause");
}
在主函数进行读取操作,建立一个Browse类,Browse类中包含了大一新生,大二学生,教师的属性,并将他们放在vector容器里,如果某个函数需要使用这些这些数据,就把他传入函数里。
只有在结束程序的时候,才把数据重新存入硬盘,增删改查操作和文件操作是分开的,这样做大大减少了代码量,提高了程序的运算效率。
?
NO.2——?caozuo.html" target="_blank">删除操作
??????在图书管理系统中,由于没有使用容器,而且做的是彻底删除,删除操作变得异常复杂,就拿删除一本书库里的书做例子,大致流程是:1、将书单进行备份,得到一份书单-副本,删除原书单的所有数据,对副本进行遍历,如果不是要删除的书就将他放在书单中,如果是要删除的书就忽略,遍历副本后将副本删除。以下是源代码:
void?Ruler::deleteBook()//删除、修改图书
{
int?i;//计数器
int?check=0;//
Bookstorage?bo;//图书
string?c;//
string?c2;//
booklist();//显示书目
int?cpbook;//计数器;
ifstream?fin("count\\booknumber.txt");//打开记录图书
fin>>cpbook;//
fin.close();//
cout<<"请输入要删除的图书的序号或者书名:";//
cin>>c;//
ifstream?fin3("Bookstorage\\booklist.txt");//
ofstream?fout4("Bookstorage\\booklist2.txt",ios::app);//
for(i=0;i<cpbook;i++){//
fin3>>bo;//
fout4<<bo;//
}
fin3.close();//
fout4.close();//
ofstream?fout5("Bookstorage\\booklist.txt",ios::binary);//
fout5.close();//
ifstream?fin2("Bookstorage\\booklist2.txt");//
ofstream?fout("Bookstorage\\booklist.txt",ios::app);//
for(?i=0;i<cpbook;i++){//
fin2>>bo;//
if(c==bo.getbook()||c==bo.getnumber())//
{
c2.assign(bo.getbook());//
c2=Address2(c2);//
ofstream?fout2(c2,ios::binary);//
fout2<<"此书已被下架;";//
fout2.close();//
check=1;//
}//
else
{
fout<<bo;//
}
?
}
fout.close();//
fin2.close();//
if(check==0)//
{
cout<<"您要删除的书不存在哦"<<endl;//
???}//
if(check==1)//
{//
cpbook--;//
ofstream?fout3("count\\booknumber.txt",ios::binary);//
fout3<<cpbook;//
fout3.close();//
}
ofstream?fout6("bookstorage\\booklist2.txt",ios::binary);//
fout6.close();//
}
这样的方法很复杂,其实,只需要对删除的书做删除标记就可以。
在学生成绩管理系统中就是如此,这种做法不仅更合适(例如:如果删错了方便数据恢复)
?
总结:
图书管理系统是我做的第一个综合性的C++实验项目,有了编写读书管理系统的经历,学生成绩管理系统很快就编写完成了(只用了三天),之前觉得编写一个图书管理系统好难好难,可是到了最后,还是被一点一点给写出来了,我想,再难走的路,只要踏踏实实一步一步走就肯定会走完,成功最大的敌人就是自卑和半途而废。
当然,这两个系统还只是实验项目。离真正的实践还很远,下一步我想我应该从实践的角度出发,考虑效率和实用性,学习MFC的知识,真正让技术服务于生活。
所以,我下一步要做的就是——班级管理系统。
?
<!--EndFragment-->