C语言模块化程序设计文件操作2王新余.docx
- 文档编号:5341572
- 上传时间:2022-12-15
- 格式:DOCX
- 页数:24
- 大小:58.03KB
C语言模块化程序设计文件操作2王新余.docx
《C语言模块化程序设计文件操作2王新余.docx》由会员分享,可在线阅读,更多相关《C语言模块化程序设计文件操作2王新余.docx(24页珍藏版)》请在冰豆网上搜索。
C语言模块化程序设计文件操作2王新余
第一篇文件操作
一概述
一、文件的概念
在我们心目中,文件是指存放在磁盘上的一些信息的集合,它具有一个唯一的名字,通过名字可以对文件进行存、修改、删除等操作。
这实际上是磁盘文件。
从广义上来看,许多外设也可以看作是一种文件,因为也可给它们取一个唯一的名字,对它们的操作也可用对磁盘文件相同的操作实现,如在DOS中定义打印机为名字是PRN的文件,当向该文件写信息时,实际上就是打印输出,定义键盘为CON的文件,当从该文件读信息时,实际上就是从键盘接受键入的字符数字。
文件是指信息输入或输出的对象。
1、“文件(file)”:
是记录在介质上的数据的集合,以文件名作为访问文件的标识。
介质:
一般是磁盘、磁带、光盘等。
2、C语言把文件看作一个字节序列,即由一连串的字节组成,以字节为单位访问,没有记录的界限(实际存在界限,例如,在FAT16文件系统中,文件的最大长度是2GB)。
3、按文件所依附的介质来分:
有磁盘文件、磁带文件、内存文件、设备文件等。
内存文件:
在内存中开辟一段空间,以文件的方式存放数据。
如、DOS虚拟磁盘驱动程序RAMDRIVE.SYS建立的虚拟磁盘上存放的文件。
Windows9.X恢复盘也建立虚拟磁盘,用于临时存放系统命令文件。
4、按文件的内容区分:
有源程序文件、目标文件、数据文件等。
5、按文件中的数据组织形式来分:
数据文件可分为ASCII码文件和二进制文件。
ASCII码文件,又称为“文本文件”(text),其每一个字节存放一个ASCII码。
二进制文件,把内存中的数据按其在内存中的存储形式存放在磁盘上。
例、十进制整数10000,
在内存中占两字节,其存放形式是:
0010,0111,0001,0000。
在二进制文件中也按这中方式存放。
在ASCII文件中,存放为31H、30H、30H、30H、30H,占五个字节,它们分别是1、0、0、0、0、0字母的ASCII码。
6、按照操作系统对磁盘文件的读写方式,文件可以分为“缓冲文件系统”和“非缓冲文件系统”。
缓冲文件系统:
操作系统在内存中为每一个正在使用的文件开辟一个读写缓冲区。
非缓冲文件系统:
操作系统不开辟读写缓冲区。
在C中自动打开的五个标准设备文件的文件结构指针(在缓冲文件系统中)和文件代号(在非缓冲文件系统中),即:
设备
流指针
文件代号
键盘(标准输入)
Stdin
0
显示器(标准输出)
Stdout
1
显示器(标准错误)
Stderr
2
串行口(标准辅助)
Stdoux
3
打印机(标准打印)
Stdprn
4
二流
在C中引入了流(stream)的概念。
它将数据的输入输出看作是数据的流入流出,这样不管是磁盘文件或是物理设备,都可看作是一种流的源或目的,视它们为同一种东西,而不管具体的物理结构。
这种把数据的输入输出操作对象,抽象为一种流,而不管它的源或目的具体结构的方法很有利于变成,而涉及流的输入输出操作函数可用于各种对象,与具体的实体无关,即具有通用性。
在C中流可分成两类,即文本流(textstream)和二进制流(binarystream)。
所谓文本流是指流中流动的数据以字符形式出现,由于文本有行的限制,因而一行流完后,必须有行结束符,C规定为“\n”,它代表了回车换行,因而在文本流中,流入时“\n”被换成回车CR和换行LF代码0DH和0AH。
而流出时,则0DH和0AH被换成“\n”。
二进制留是指流动着的二进制数字序列,若流中有字符,则用一字节的二进制ASCII码表示,若是数字,则用一个字节的二进制数表示。
在流入流出时,对“\n”符号不进行转换,因而流中流入的字节数和流出的字节数相同。
由此可以看出,二进制流比文本流节省空间,且不用进行对“\n”的转换,这样可大大加快流的速度,提高效率,因而对于含有大量数字信息的数字流,可用二进制流方式,而含有大量字符信息的流,可采用文本流方式。
在C语言中流就是一种文件形式,它实际上就表示一个文件或设备。
三文件类型指针
要调用一个文件,需要有以下的信息:
文件操作方式等
文件当前的读写位置
与该文件对应的内存缓冲区的地址
缓冲区中未被处理的字符串
缓冲文件系统会为每一个文件系统开辟一个“文件信息区”,在stdio.h中,它被定义为FILE类型数据。
typedefstruct
{
int_fd; /*文件号*/
int_cleft; /*缓冲区中剩下的字节数*/
int_mode; /*文件操作模式*/
char*_nextc;/*下一个字节的位置*/
char*_buff; /*文件缓冲区位置*/
}FILE;
其中:
每个成员就是用来存放有关文件的各种信息的数据项。
定义文件指针变量的一般形式为:
FILE*文件结构指针变量名
例如、FILE*fp;
注意:
只有通过文件指针,才能调用相应的文件。
四文件的打开与关闭
文件操作的过程:
对磁盘文件的操作必须“先打开,后读写,最后关闭”。
“打开”文件的含义:
以某中方式从磁盘上查找指定的文件或创建一个新文件。
FILE*fopen(constchar*filename,constchar*mode);
filename:
文件名(可以包含逻辑驱动器、路径、文件名、扩展名)
mode:
打开方式
FILE*:
返回值
如:
FILE*fp;
fp=fopen("file1","r");
如果成功打开,返回一个指向被打开文件的文件信息区的起始地址;
如果打开失败,返回一个NULL指针。
文件打开方式
含义
"r"(只读)
为输入打开一个文本文件
"w"(只写)
为输出打开一个文本文件
"a"(追加)
为追加打开一个文本文件
"rb"(只读)
为输入打开一个二进制文件
"wb"(只写)
为输出打开一个二进制文件
"ab"(追加)
为追加打开一个二进制文件
"r+"(读写)
为读/写打开一个文本文件
"w+"(读写)
为读/写创建一个文本文件
"a+"(读写)
为读/写打开一个文本文件
"rb+"(读写)
为读/写打开一个二进制文件
"wb+"(读写)
为读/写创建一个二进制文件
"ab+"(读写)
为读/写打开一个二进制文件
说明:
1、打开文件的方式,必须与文件的属性兼容。
例如,不能以"w"和"a"方式打开具有“只读”属性的文件。
但可以以任何方式打开“隐藏”属性文件。
2、DOS/Windows中,无“只写”文件属性,一个文件可写,同时意味着可读。
3、用带"r"的方式("r"、"rb"、"r+"、"rb+")打开文件时,若文件不存在,则返回NULL指针。
一般用以下方式检查是否成功打开:
FILE*fp;
if((fp=fopen("file1","r"))==NULL)
{
printf("cannotopenthisfile\n");
exit(0);
}
exit(0)是程序返回操作系统。
4、在C中,用带"a"或带"w"的方式打开文件时,若文件不存在,则创建该文件。
但fopen()函数仍可能因为磁盘写保护或目录满而失败。
5、在C中,用带"a"或带"w"的方式打开文件时,若文件已存在,"a"方式在原文件后追加数据,"w"方式把原文件删除、并重新创建一个相同名字的文件。
文件的关闭:
“关闭”文件的作用:
(1)使文件指针fp与文件脱离。
(2)刷新文件输入/输出缓冲区。
关闭方法:
fclose(fp);
五文件的读写
一、fputc()/fgetc()
intfputc(intc,FILE*fp)----把字符c写入文件fp,成功时返回字符c的ASCII码,失败时返回EOF(在stdio.h中,符号常量EOF的值等于-1)。
intfgetc(FILE*fp)----从文件fp中读一个字符,返回读得的字符。
对于文本文件,遇文件尾时返回EOF。
对于二进制文件,用feof(fp)判别是否遇文件尾。
feof(fp)=1说明遇文件尾。
【例一】、从文本文件test中顺序读入文件内容,并在屏幕上显示出来。
#include"stdio.h"
voidmain()
{
FILE*fp;
charch;
fp=fopen("test","r");
if(fp==NULL)
{
printf("cannotopentest\n");
exit(0);
}
ch=fgetc(fp);
while(ch!
=EOF)
{
putchar(ch);
ch=fgetc(fp);
}
fclose(fp);
}
【例二】、从二进制文件test中读入文件内容.
#include"stdio.h"
voidmain()
{
FILE*fp;
charch;
fp=fopen("test","rb");
if(fp==NULL)
{
printf("cannotopentest\n");
exit(0);
}
while(!
feof(fp))
{
ch=fgetc(fp);
....
}
fclose(fp);
}
【例三】 从键盘输入一些字符,逐个把它们送入磁盘文件,知道从键盘输入#为止。
#include"stdio.h"
voidmain()
{
FILE*fp;
charch;
charfilename[10];/*文件名*/
printf("Inputfilename\n");
scanf("%s\n",filename);/*从键盘输入文件名*/
if((fp=fopen(filename,"w"))==NULL)/*打开文件*/
{
printf("cannotopenfile%s\n",filename);
exit(0);
}
ch=getchar();
while(ch!
='#')/*从键盘读入字符,直到#为止*/
{
fputc(ch,fp);
putchar(ch);
ch=getchar();
}
fclose(fp);/*关闭文件*/
}
【例四】、将一个磁盘文件的内容复制到另一个磁盘文件。
#include"stdio.h"
voidmain()
{
FILE*in,*out;
charch;
charinfile[10],outfile[10];
printf("Entertheinfilename\n");
scanf("%s",infile);
printf("Entertheoutfilename\n");
scanf("%s",outfile);
if((in=fopen(infile,"r"))==NULL)
{printf("cannotopeninfile%s\n",infile);
exit(0);
}
if((out=fopen(outfile,"w"))==NULL)
{printf("cannotopenoutfile%s\n",outfile);
exit(0);
}
while(!
feof(in))fputc(fgetc(in),out);
fclose(in);
fclose(out);
}
二、fread()/fwrite()
size_tfread(void*buffer,size_tsize,size_tcount,FILE*fp);
从文件fp中读入count次,每次读size字节,读入的信息存在buffer指针指向的缓冲区。
函数返回值等于实际读入的次数(可能少于count)。
size_tfwrite(void*buffer,size_tsize,size_tcount,FILE*fp);
将buffer地址开始的信息,写瘀?
?
?
?
入count次,每次写size字节至文件fp中。
函数返回值等于实际写入的次数(可能少于count)。
【例五】、结构体类型数据。
structstudent_type
{
charname[10];
intnum;
intage;
charaddr[30];
}stu[40];
写入文件:
for(i=0;i<40;i++)/*每次写一个学生*/
fwrite(&stu[i],sizeof(structstudent_type),1,fp);
或:
写一次
fwrite(stu,sizeof(structstudent_type),40,fp);
从磁盘文件读出:
for(i=0;i<40;i++)
fread(&stu[i],sizeof(structstudent_type),1,fp);
或:
fread(&stu[i],sizeof(structstudent_type),40,fp);
【例六】从键盘上输入一批学生数据,然后存储到磁盘上。
#include"stdio.h"
#defineSIZE4
structstudent_type
{
charname[10];
intnum;
intage;
charaddr[15];
}stud[SIZE];
voidsave();/*原型 */
voidload();/*原型 */
voidmain()
{inti;
for(i=0;iSIZE;i++)/*从键盘读入数据*/
scanf("%s%d%d%s",
stud[i].name,&stud[i].num,&stud[i].age,stud[i].addr);
save();/*存盘*/
load();/*从盘读出*/
for(i=0;iSIZE;i++)/*屏幕上显示*/
printf("%-10s%4d%4d%-15s\n",stud[i].name,stud[i].num,stud[i].age,stud[i].addr);
}
voidsave()
{FILE*fp;
inti;
if((fp=fopen("stu_list","wb"))==NULL)
{
printf("cannotopenfile\n";
exit(0);
}
for(i=0;iSIZE;i++)
if(fwrite(&stud[i],sizeof(structstudent_type),1,fp)!
=1)
printf("filereaderror\n");
}
voidload()
{FILE*fp;
inti;
if((fp=fopen("stu_list","rb"))==NULL)
{
printf("cannotopenfile\n";
return;
}
for(i=0;iSIZE;i++)
if(fread(&stud[i],sizeof(structstudent_type),1,fp)!
=1)
{
if(feof(fp))return;
printf("filereaderror\n");
}
}
三、fprintf()/fsacnf()函数
fprintf(文件指针,格式控制,变量列表);
fscanf(文件指针,格式控制,变量地址列表);
除增加“文件指针”外,与printf()/scanf()用法相同。
四、其它读写磁盘函数
intputw(intw,FILE*fp)/*整数w写入文件fp瘀?
?
?
?
*/
intgetw(FILE*fp)/*从文件fp读一个整数*/
char*fgets(char*str,intn,FILE*fp);
从文件fp读n-1个字节到str,str最后一个字节加'\0'。
intfputs(constchar*str,FILE*fp)
把str写入fp。
六文件的定位
文件指针FILE*fp中,包含一个读写位置指针char*_nextc,它指向下一次文件读写的位置。
typedefstruct
{
int_fd; /*文件号*/
int_cleft; /*缓冲区中剩下的字节数*/
int_mode; /*文件操作模式*/
char*_nextc;/*下一个字节的位置*/
char*_buff; /*文件缓冲区位置*/
}FILE;
每当进行一次读写后,该指针自动指向下一次读写的位置。
当文件刚打开或创建时,该指针指向文件的开始位置。
可以用函数ftell()获得当前的位置指针,也可以用rewind()/fseek()函数改变位置指针,使其指向需要读写的位置。
1、rewind()函数
原型:
voidrewind(FILE*fp)
作用:
使文件fp的位置指针指向文件开始。
【例一】把一个文件的内容显示在屏幕上,并同时复制到另一个文件。
#include"stdio.h"
voidmain()
{
FILE*fp1,*fp2;
fp1=fopen("file1.c","r");/*源文件*/
fp2=fopen("file2.c","w");/*复制到file2.c*/
while(!
feof(fp1))putchar(fgetc(fp1));/*显示到屏幕上*/
rewind(fp1);/*fp回到开始位置*/
while(!
feof(fp1))fputc(fgetc(fp1),fp2);
fclose(fp1);
fclose(fp2);
}
2、fseek()函数
原型:
intfssek(FILE*fp,longoffset,intorigin);
功能:
把文件fp的位置指针从起始点origin开始,移动offset字节。
成功返回0,失败返回非0。
起始点origin
符号常量
值
文件开始位置
SEEK_SET
0
当前位置
SEEK_CUR
1
文件尾
SEEK_END
2
【例二】在磁盘文件stud_dat上,存有10个学生(0~9)的数据,读出1、3、5、7、9号学生数据,并在屏幕上显示出来。
#include"stdio.h"
structstudent_type
{
charname[10];
intnum;
intage;
charsex;
}stud[10];
voidmain()
{
inti;
FILE*fp;
if((fp=fopen("stud_dat","rb"))==NULL)
{
printf("cannotopenfile\n");
exit(0);
}
for(i=0;i<10;i+=2)
{
fseek(fp,i*sizeof(structstudent_type),SEEK_SET);
fread(&stu[i],sizeof(structstudent_type),1,fp);
printf("%s%d%d%c\n",
stud[i].name,stud[i].num,stud[i].age,stud[i].sex);
}
fclose(fp);
}
3、ftell()
原型:
longftell(FILE*fp);
功能:
获得文件fp的当前位置指针。
若返回-1则失败。
4、feof()
原型:
intfeof(FILE*fp);
功能:
判断fp的当前位置指针是否在文件尾。
不在文件尾返回0。
七文件缓冲区函数
1、清除文件缓冲区函数
intfflush(FILE*fp);
intfflushall(void);
fflush()函数将清除由fp执行的文件缓冲区的内容,常用于写完一些数据后,立即用该函数清除缓冲区,以免误操作,破坏原来数据。
Fflushall()函数清除所有打开的文件所对应的文件缓冲区。
2、设置文件缓冲区函数
voidsetbuff(FILE*fp,char*buf);
voidsetvbuf(FILE*fp,char*buf,inttype,unsignedsize);
这两个函数将使得打开文件后,用户可建立自己的文件缓冲区(由buf指针给出地址),而不使用fopen()函数打开文件时设定的缓冲区。
对于setbuf函数,buf指出的缓冲区长度由头文件stdio.h定义的宏BUFSIZE的值决定,缺省值为512字节。
当选定buf为空时,setbuf函数将使得文件I/O操作不带缓冲。
而对setvbuf函数,则有malloc函数来分配缓冲区,参数size指明缓冲区的长度(必须大于0),而参数type则表示了缓冲的类型,其值可取如下的值:
_IOFBF文件全部缓冲,即缓冲区装满后,才能对文件进行写入或读出
_IOLBF文件行缓冲,即缓冲区接收到一个换行符,才进行写入或读出
_IONBF文件不缓冲,此时参数buf、size均被忽略,直接写文件或读文件
使用这两个函数时要注意,它们必须用打开文件之后或调用fseek之后,否则文件缓冲区将出现两个,使数据混乱。
八出错的检测
在文件操作时,如果出错,除了操作函数的返回值有所反应外(如fopen()函数返回NULL),还可以用ferror()函数获得是否出错。
原型:
intferror(FILE*fp)
功能:
若上一次文件操作未出错,返回0;否则返回非0。
文件操作出现错误后,该错误信息将一直保留
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 语言 模块化 程序设计 文件 操作 新余