《第九章保存程序数据》由会员分享,可在线阅读,更多相关《第九章保存程序数据(22页珍藏版)》请在金锄头文库上搜索。
1、第九章 保存程序数据 主要内容案例:将“学生信息管理系统”的学生信息进行永久保存使用文件保存学生信息案例实施学生练习拓展小结在本章,将继续完善在本章,将继续完善“ “学生信息管理系统学生信息管理系统” ”案例程序。案例程序。本章可以实现对学生完整信息的长期保存,能将学生本章可以实现对学生完整信息的长期保存,能将学生的基本信息保存在磁盘上。当需要的时候可以从磁盘的基本信息保存在磁盘上。当需要的时候可以从磁盘上读出数据,当数据被修改的时候,能重新写回磁盘,上读出数据,当数据被修改的时候,能重新写回磁盘,保证磁盘上的数据和内存数据一致。具体包括:保证磁盘上的数据和内存数据一致。具体包括:(1 1)将
2、学生的完整信息保存在磁盘的指定位置;)将学生的完整信息保存在磁盘的指定位置;(2 2)在程序运行的时候可以加载指定文件中的学生信)在程序运行的时候可以加载指定文件中的学生信息;息;案例:保存学生信息它一般指存储在外部介质上数据的集合。操作系统是以文件为它一般指存储在外部介质上数据的集合。操作系统是以文件为单位对数据进行管理的。单位对数据进行管理的。根据文件的组织形式,根据文件的组织形式,C C语言将文件分为文本文件和二进制文语言将文件分为文本文件和二进制文件两种。件两种。按文本文件存放数据时,每个字符占一个字节,并且按其按文本文件存放数据时,每个字符占一个字节,并且按其ASCIIASCII码存
3、储到文件中,所以文本文件也称为码存储到文件中,所以文本文件也称为ASCIIASCII文件。它文件。它的每个字节放一个的每个字节放一个ASCIIASCII代码,代表一个字符。代码,代表一个字符。按二进制文件存放数据,其存放形式与数据在内存中的存储形按二进制文件存放数据,其存放形式与数据在内存中的存储形式相同,也就是说数据是按其在内存中的存储形式原样输出式相同,也就是说数据是按其在内存中的存储形式原样输出到磁盘上存放。所以不需要转换,从而可以提高效率而且也到磁盘上存放。所以不需要转换,从而可以提高效率而且也能节省存储空间。能节省存储空间。在在C C语言中,对文件的读写都是通过库函数实现的。语言中,
4、对文件的读写都是通过库函数实现的。使用文件保存学生信息-文件概念文件的处理必须包括:文件的处理必须包括:打开文件打开文件读或写文件、读或写文件、关闭文件关闭文件使用文件保存学生信息-文件操作磁盘文件内存储器数据存储区磁盘文件内存储器数据存储区磁盘文件内存储器数据存储区磁盘文件内存储器数据存储区标准输入输出函数,用标准输入输出函数,用fopenfopen() () 函数来实现打开文件。函数来实现打开文件。fopenfopen函数的调用方式通常是:函数的调用方式通常是: FILE *FILE *fs fs; ; fs fs= =fopenfopen(文件名文件名,打开模式打开模式);其中其中 fs
5、 fs是一个文件指针,文件指针是是一个文件指针,文件指针是FILEFILE类型,类型,FILEFILE类型已由类型已由系统声明,可直接使用。通过文件指针,可以对它所指向的文系统声明,可直接使用。通过文件指针,可以对它所指向的文件进行各种操作。件进行各种操作。fopenfopen是一个系统函数,有两个参数,其中文件名包括文件所在是一个系统函数,有两个参数,其中文件名包括文件所在的全部路径,路径的分隔符的全部路径,路径的分隔符应采用转义字符的形式。文件应采用转义字符的形式。文件可以是文本文件,也可以是二进制文件。可以是文本文件,也可以是二进制文件。打开模式是指定所要打开的文件读写方式,打开模式要用
6、小写,打开模式是指定所要打开的文件读写方式,打开模式要用小写,并且要用双引号括起来并且要用双引号括起来 使用文件保存学生信息-打开文件使用文件保存学生信息-打开文件Mode(方式)意义r(只读) 打开一个文本文件,只允许读数据w(只写)创建一个文本文件,只允许写数据a(追加) 打开一个文本文件,并在文件的末尾增加数据rb(只读)打开一个二进制文件,只允许读数据wb(只写)创建一个二进制文件,只允许写数据ab(追加)打开一个二进制文件,并在文件的末尾增加数据r+(读写)打开一个文本文件,允许读和写w+(读写)建立一个文本文件,允许读和写a+(读写)打开一个文本文件,允许读或在文件末尾追加数据rb
7、+(读写)打开一个二进制文件,允许读和写wb+(读写)建立一个二进制文件,允许读和写ab+(读写)打开一个二进制文件,允许读或在文件末尾追加数据如果不能实现如果不能实现“ “打开打开” ”文件的任务,文件的任务,fopenfopen函数将会带回一个函数将会带回一个出错信息,出错的原因可能是用出错信息,出错的原因可能是用“ “r”r”方式打开一个并不存在方式打开一个并不存在的文件;磁盘出故障;磁盘已经满了,无法建立一个新文件的文件;磁盘出故障;磁盘已经满了,无法建立一个新文件等。此时等。此时fopenfopen函数将带回一个空指针值函数将带回一个空指针值NULLNULL。常常用下面。常常用下面的
8、方法打开一个文件:的方法打开一个文件:if(fsif(fs=fopen(file1, r)=NULL)=fopen(file1, r)=NULL) printf(cannotprintf(cannot open this filen); open this filen);exit(0);exit(0); 使用文件保存学生信息-打开文件freadfread函数和函数和函数和函数和fwritefwrite函数,函数,函数,函数,一般调用形式为:一般调用形式为:fread(buffer,size,count,fsfread(buffer,size,count,fs); );fwrite(buffer
9、,size,count,fsfwrite(buffer,size,count,fs); );其中:其中:bufferbuffer是一个指针,对是一个指针,对freadfread来说,它是读入来说,它是读入数据的存放地址,对数据的存放地址,对fwritefwrite来说,它是要输出数据的来说,它是要输出数据的地址,都是指起始地址。地址,都是指起始地址。sizesize要读写的字节数。要读写的字节数。countcount要进行读写多少个要进行读写多少个sizesize字节的数据项。字节的数据项。fs fs文件类型的指针。文件类型的指针。使用文件保存学生信息-读写文件Student *Student
10、 *stustu; ;stustu = (Student *) = (Student *)malloc(totalmalloc(total* *sizeof(Studentsizeof(Student););假设学生的数据已经存放在磁盘文件中,并且存放了假设学生的数据已经存放在磁盘文件中,并且存放了currentcurrent个学生的信息,这时可以用下面的个学生的信息,这时可以用下面的forfor语句和语句和 freadfread函数读入函数读入currentcurrent个学生的数据:个学生的数据:for(ifor(i=0;i=0;icurrent;icurrent;i+)+) fread(
11、stu+ifread(stu+i), ), sizeof(Studentsizeof(Student), 1, ), 1, fs fs); );可以用可以用fwritefwrite函数把内存中的学生数据输出到磁盘文件中去:函数把内存中的学生数据输出到磁盘文件中去:for(ifor(i=0;i=0;icurrent;icurrent;i+)+) fwrite(stu+ifwrite(stu+i), ), sizeof(Studentsizeof(Student), 1, ), 1, fs fs); );使用文件保存学生信息-读写文件fseekfseek函数可以实现改变文件的位置指针。调用形式为:
12、函数可以实现改变文件的位置指针。调用形式为: fseekfseek( (文件指针,位移量,起始点文件指针,位移量,起始点) )其中起始点用其中起始点用0 0、1 1和和2 2代替,代替,0 0代表代表“ “文件的开始文件的开始” ”,1 1代表代表“ “当前位置当前位置” ”,2 2代表代表“ “文件的末尾文件的末尾” ”位移量是指以位移量是指以“ “起始点起始点” ”为基点,向前移动的字节数(该位移量可以为正数,也可为基点,向前移动的字节数(该位移量可以为正数,也可以是负数)。以是负数)。ANSI CANSI C要求位移量是要求位移量是longlong型数据,这样当文件的长度大于型数据,这样
13、当文件的长度大于64K64K时不会出问题。时不会出问题。ANSI CANSI C标准规定在数字的末尾加一个字标准规定在数字的末尾加一个字母母L L,表示是,表示是longlong型。型。同时同时fseekfseek函数一般用于二进制文件,因为文本文件要发生字函数一般用于二进制文件,因为文本文件要发生字符转换,计算位置时往往发生混乱。符转换,计算位置时往往发生混乱。可以用:可以用: succsucc = = fseek(fsfseek(fs, 0, SEEK_END);, 0, SEEK_END);使得使得fseekfseek函数函数返回文件的末尾。返回文件的末尾。使用文件保存学生信息-读写文件
14、ftellftell()()函数的作用是得到文件中的当前位置,用相对于文件开函数的作用是得到文件中的当前位置,用相对于文件开头的位移量来表示。由于文件中的位置指针经常移动,人们头的位移量来表示。由于文件中的位置指针经常移动,人们往往不容易知道当前的位置。用往往不容易知道当前的位置。用ftellftell函数可以得到当前的位函数可以得到当前的位置,如果置,如果ftellftell函数返回值为函数返回值为-1L-1L,表示出错。如:,表示出错。如:i=i=ftell(fsftell(fs); );if(iif(i=-1l)=-1l)printf(errornprintf(errorn););使用文
15、件保存学生信息-读写文件 在使用完一个文件后应该关闭它,以防止它再被误用。在使用完一个文件后应该关闭它,以防止它再被误用。“ “关闭文件关闭文件” ”就就是使文件指针变量不指向该文件,也就是文件指针变量与文件是使文件指针变量不指向该文件,也就是文件指针变量与文件“ “脱钩脱钩” ”,此后不能再通过该指针对原来与其相联系的文件进行读写操作。除非,此后不能再通过该指针对原来与其相联系的文件进行读写操作。除非再次打开,使该指针变量重新指向该文件。再次打开,使该指针变量重新指向该文件。 用用fclosefclose函数关闭文件。函数关闭文件。fclosefclose函数的调用形式为:函数的调用形式为:
16、 fclosefclose( (文件指针文件指针) ); fclosefclose函数也带回一个值,当顺利地执行了关闭操作,则返回值为函数也带回一个值,当顺利地执行了关闭操作,则返回值为0 0,否,否则返回为则返回为EOFEOF(-1-1)。)。 前面曾经把打开文件(用前面曾经把打开文件(用fopenfopen函数)时所带回的指针赋给了函数)时所带回的指针赋给了fs fs,今通过,今通过 fs fs把该文件关闭,使其不再指向该文件。在编写程序的时候,应该养成在把该文件关闭,使其不再指向该文件。在编写程序的时候,应该养成在程序终止之前关闭所有文件的习惯,如果不关闭文件将可能造成数据的程序终止之前
17、关闭所有文件的习惯,如果不关闭文件将可能造成数据的丢失。丢失。使用文件保存学生信息-关闭文件 intint save() save() intint count; count; FILE *FILE *fs fs; ; fs fs = = fopen(StudentData.datfopen(StudentData.dat, , wbwb);); if (if (fs fs = NULL) = NULL) printfprintf(不能打开文件不能打开文件n);n); return 1;return 1; count = count = fwrite(stufwrite(stu, , size
18、of(Studentsizeof(Student), current, ), current, fs fs); ); fclose(fsfclose(fs); ); if (count != current)if (count != current) printfprintf(保存失败保存失败n);n); return 1;return 1; printfprintf(保存成功保存成功n);n); return 0;return 0; 案例实施-使用文件保存学生信息 intint load() load() FILE *FILE *fsfs; ; intint count; count; in
19、tint succsucc; ; fsfs = = fopen(StudentData.datfopen(StudentData.dat, , rbrb);); if (if (fsfs = NULL) = NULL) printfprintf(不能打开文件不能打开文件n);n); return 1;return 1; succsucc = = fseek(fsfseek(fs, 0, SEEK_END);, 0, SEEK_END); if (if (succsucc != 0) != 0) printfprintf(文件操作失败文件操作失败n);n); fclose(fsfclose(fs
20、); ); return 1;return 1; count = count = ftell(fsftell(fs); ); fseek(fsfseek(fs, 0, SEEK_SET);, 0, SEEK_SET); current = count/current = count/sizeof(Studentsizeof(Student); ); count = count = fread(stufread(stu, , sizeof(Studentsizeof(Student), current, ), current, fsfs); ); fclose(fsfclose(fs); );
21、if (count != current)if (count != current) printfprintf(读文件失败读文件失败n);n); return 1;return 1; printfprintf(读文件成功读文件成功n);n); return 0;return 0; 案例实施-使用文件保存学生信息到现在为止,已经完成对学生信息进行永久保存了,即将学生到现在为止,已经完成对学生信息进行永久保存了,即将学生的完整信息以指定的文件名保存到磁盘上指定的位置。同时也的完整信息以指定的文件名保存到磁盘上指定的位置。同时也可以将磁盘上文件中的学生信息读入。现在到了你们完成图书可以将磁盘上文件中
22、的学生信息读入。现在到了你们完成图书信息管理系统中的数据保存和加载的时候了。信息管理系统中的数据保存和加载的时候了。继续完善你的案例程序,使之可以将图书信息在磁盘上进行长继续完善你的案例程序,使之可以将图书信息在磁盘上进行长期保存,同时又可以将磁盘上文件的信息读入。具体要求:期保存,同时又可以将磁盘上文件的信息读入。具体要求:(1 1)编写能保存图书信息的案例程序;)编写能保存图书信息的案例程序;(2 2)编写能加载图书信息的案例程序;)编写能加载图书信息的案例程序;(3 3)在)在CodeBlocksCodeBlocks环境下调试你的程序,使之正确运行。环境下调试你的程序,使之正确运行。学生
23、练习拓展-open函数 open()open()函数的作用是打开文件函数的作用是打开文件, , 其调用格式为其调用格式为: : intint open(constopen(const char *path, char *path, intint access , unsigned mode); access , unsigned mode); 参数参数pathpath是要打开的文件名,是要打开的文件名,accessaccess是打开的模式,是打开的模式,modemode是修饰符,可选项。是修饰符,可选项。表示文件的属性,修饰符可以有多个表示文件的属性,修饰符可以有多个, , 但基本模式只能有一
24、个。但基本模式只能有一个。 文件文件open()open()函数打开成功函数打开成功, , 返回值就是文件描述字的值返回值就是文件描述字的值( (非负值非负值), ), 否则返回否则返回-1-1。 比如在案例程序比如在案例程序“ “学生信息管理系统学生信息管理系统” ”中要在磁盘上保存学生信息。如果以中要在磁盘上保存学生信息。如果以StudentData.datStudentData.dat文件名保存在当前路径下,并且是以二进制文件保存。则基文件名保存在当前路径下,并且是以二进制文件保存。则基本模式为本模式为O_WRONLYO_WRONLY。其打开文件代码为:。其打开文件代码为: fhandl
25、efhandle= =open(StudentData.datopen(StudentData.dat, O_WRONLY|O_CREAT|O_TRUNC);, O_WRONLY|O_CREAT|O_TRUNC); 如果现在想读取上面存储的学生信息,这个时候首先是以只读方式打开数据如果现在想读取上面存储的学生信息,这个时候首先是以只读方式打开数据库文件。其代码是:库文件。其代码是: fhandlefhandle= =open(StudentData.datopen(StudentData.dat, O_RDONLY);, O_RDONLY);基本模式含义修饰符含义O_RDONLY只读O_APP
26、END文件指针指向末尾O_WRONLY只写O_CREAT文件不存在时创建文件,属性按基本模式属性O_RDWR读写O_TRUNC若文件存在,将其长度缩为0,属性不变O_BINARY打开一个二进制文件O_TEXT打开一个文字文件拓展-write函数writewrite函数写一块数据到文件中。其调用格式为函数写一块数据到文件中。其调用格式为: : intint write(intwrite(int handle, void * handle, void *bufbuf, unsigned , unsigned lenlen););参数参数bufbuf读出的数据,读出的数据,lenlen是写入的字节,
27、函数返回实际写是写入的字节,函数返回实际写入的字节。入的字节。如上面打开了文件,同时如上面打开了文件,同时openopen函数的返回值赋给了整形变函数的返回值赋给了整形变量量fhandlefhandle。学生数据保存在结构体数组。学生数据保存在结构体数组stustu中,学生数目中,学生数目为为currentcurrent个,则把学生信息写入打开的数据库文件中的代个,则把学生信息写入打开的数据库文件中的代码为:码为:write(fhandlewrite(fhandle, , stustu, , sizeof(Studentsizeof(Student)*current);)*current);拓
28、展-read函数read() read() 从文件读取一块数据。其调用格式为从文件读取一块数据。其调用格式为: :intint read(intread(int handle, void * handle, void *bufbuf, unsigned , unsigned lenlen); );参数参数bufbuf保存读出的数据,保存读出的数据,lenlen是读取的字节。函数返回实是读取的字节。函数返回实际读出的字节。际读出的字节。同样可以把刚刚保存的学生信息从新加载。则代码为:同样可以把刚刚保存的学生信息从新加载。则代码为:read(fhandleread(fhandle, , stust
29、u, , sizeof(Studentsizeof(Student)*current);)*current);拓展-lseek函数lseeklseek()()函数定位到指定的位置,其调用格式为函数定位到指定的位置,其调用格式为: :long long lseek(intlseek(int handle, long offset, handle, long offset, intint fromwherefromwhere); );参数参数offsetoffset是移动的量,是移动的量,fromwherefromwhere是移动的基准位置,取是移动的基准位置,取值和前面讲的值和前面讲的fseek
30、fseek()()一样,一样,SEEK_SETSEEK_SET:文件首部;:文件首部;SEEK_CURSEEK_CUR:文件当前位置;:文件当前位置;SEEK_ENDSEEK_END:文件尾。此函:文件尾。此函数返回执行后文件新的存取位置。数返回执行后文件新的存取位置。拓展-close函数同样的,当打开了文件不用的时候,也需要关闭文件,在同样的,当打开了文件不用的时候,也需要关闭文件,在这里关闭文件使用这里关闭文件使用closeclose函数。函数。close()close()关闭一个句柄,其调关闭一个句柄,其调用格式为:用格式为:intint close(intclose(int handl
31、e); handle);同样,在前面的同样,在前面的openopen函数中,调用它打开一个文件,同时函数中,调用它打开一个文件,同时返回一个句柄,赋给了变量返回一个句柄,赋给了变量fhandlefhandle。现在就可以通过。现在就可以通过closeclose函数来关闭文件。其代码是:函数来关闭文件。其代码是:close(fhandleclose(fhandle); ); 本章介绍了C语言程序设计的文件操作,并应用文件操作完善了案例程序“学生信息管理系统”的设计,通过使用文件操作实现了对学生信息的长期保存以及保存数据如何加载。文件是C语言中很重要的内容,在许多实际的C程序中都包含文件处理。希望学生在实践中掌握文件的使用。小结