C语言文件存取.docx
- 文档编号:10251331
- 上传时间:2023-05-24
- 格式:DOCX
- 页数:25
- 大小:30.87KB
C语言文件存取.docx
《C语言文件存取.docx》由会员分享,可在线阅读,更多相关《C语言文件存取.docx(25页珍藏版)》请在冰点文库上搜索。
C语言文件存取
C语言:
文件存取初步
在磁盘上数据的存储是以OS文件为单位的。
OS文件可分为两大类:
文本(Text)文件和二进制(Binary)文件。
Text文件可以在屏幕上或打印机上
打印(例如在某个TextEditor中打开),是肉眼可读的;而二进制文件,如果也在TextEditor中打开,
你看到的可能一片“乱码”。
其实,任何文件在磁盘上,存储的都是二进制代码,以字节为单位,每一字
节由8个二进制位(0或1)组成。
因此,C语言统称它为字节流(ByteStream)。
如果说两者有区别,
区别在于,对于ASCII文本文件,每一个字节中的二进制码恰好代表一个ASCII字符,而且,因为文本
文件一般是用于显示或打印的目的,字节流被分成一系列“行”,每一行以回车符和换行符(’\r’’\n’)结尾;
而二进制文件,每个字节的二进制码可能不对应于任何可印刷字符,也没有“行”的概念。
在C语言中,这两种文件都可通过文件I/O库函数(也称流函数)存取(读写)。
为了使用键盘输入、
屏幕输出和打印机输出,C语言(以及DOS)把这些设备也视为文件,称为设备文件。
于是,C程序可以
用同样的文件I/O(输入输出)函数存取磁盘文件和设备文件。
在stdio.h文件中列出了所有ANSIC标准文件I/O库函数原型及其用到的数据结构的定义。
其中,最重要
的数据结构是FILE结构体:
FILE结构体:
typedefstruct{
shortlevel;/*fill/emptylevelofbuffer*/
unsignedflags;/*Filestatusflags*/
charfd;/*Filedescriptor*/
unsignedcharhold;/*Ungetccharifnobuffer*/
shortbsize;/*Buffersize*/
unsignedchar*buffer;/*Datatransferbuffer*/
unsignedchar*curp;/*Currentactivepointer*/
unsignedistemp;/*Temporaryfileindicator*/
shorttoken;/*Usedforvaliditychecking*/
}FILE;
任何文件在读写前必须打开。
文件标准I/O是使用缓冲区的。
当用fopen()打开一个文件时,存取该文件
用的缓冲区在内存中被fopen()建立,fopen()也同时建立一个与存取该文件有关的FILE结构体,并返回
指向该FILE结构体的指针。
注意,在这个FILE结构体中,指针变量buffer正是指向所建缓冲区的指针。
FILE结构体还包含与存取该文件有关的信息,当文件在读写过程中,有些信息也在相应地更新。
例如,
curp指针总是指向缓冲区中当前要读写的位置。
你无须了解FILE结构体的每一成员的细节,你一般也用不着直接访问FILE结构体中的成员变量,你只须
知道fopen()返回的FILE指针是与所打开的文件相联系的,或者说得简单些,这个FILE指针指向的就是
所打开的文件(虽然实际指向的是与所打开的文件相联系的FILE结构体)。
随后,当用其他标准I/O函数
读或写文件时,你只是简单地引用FILE指针,以便告诉C,你要读写的是那一个文件。
用来读写已打开
文件的标准I/O函数主要包括:
fgetc():
读单个字符,fgets():
读n个字符,fputc():
写单个字符,fputs():
写一字符串。
fscanf():
读一字符序列,并按接收变量的类型转换。
fprintf():
把输出变量的内容转换成字符序列,写到文件上。
fread():
读n个字节,fwrite():
写n个字节。
(常用于读写二进制文件)
rewind(),fseek():
移动文件当前读写位置,ftell():
返回文件当前读写位置
还要记住,读写结束后,应当用fclose()关闭所打开的文件,以确保缓冲区的内容被写到文件上。
标准(ANSIC)输入输出函数:
打开文件:
FILE*fopen(constchar*path,constchar*mode);
其中,path字符串指定要打开的文件名,如“C:
\Dir1\File1.txt”;
mode字符串指定对该文件的存取方式,如“r”。
mode字符串可以是以下字符的组合:
r(读),w(写),a(追加),+(读和写),t(文本方式),b(二进制方式)
如果不指定t或b,则默认为t;如果有r或a,则文件必须已存在;如果w,则当文件存在时,
清除原内容后再写,否则创建新文件。
a与w不同,它不清除原内容,而是在原内容之后补写。
+和r、w、或a连用,容许读和写,是否要求原文件存在或是否创建新文件,取决于r、w或a。
fopen()函数返回FILE指针,你用FILE指针变量(以下为叙述方便,设为Fp)接收这个返回值,
随后在用其他I/O函数读写该文件时,要引用这个FILE指针变量Fp。
或者粗略地说,Fp就是
这个fopen()打开的、随后要读写的文件。
如果打开不成功,fopen()返回NULL,NULL在stdio.h
中被#define为整数0)。
例:
FILE*Fp;
Fp=fopen(“C:
\Dir1\File1.txt”,“r”);/*为读打开,Text方式*/
Fp=fopen(“C:
\Dir1\File1.txt”,“r+”);/*为读写打开,r要求文件必须存在,Text方式*/
Fp=fopen(“C:
\Dir1\File1.txt”,“wb+”);/*为读写打开,Binary方式*/
fprintf(Fp,“%d,%d,%d”,i,j,k);/*往打开的Fp文件上写*/
关于文件当前位置指针:
所有I/O函数都维护文件读写的当前位置指针。
当fopen()打开文件成功时,当前位置指针指向
文件的开始处(第一个字节)。
随后,你可顺序读或写文件。
所有执行读或写功能的函数(见后),
在读或写n个字节后(n>=1),当前位置指针均移动n个字节,即指针自动移动到下一次要读或写
的位置(当然不会超过文件尾)。
以下在介绍每个函数时,不再特别说明。
你也能调用rewind()、fseek()、fsetpos()等函数重置当前位置指针后再读写(所谓“随机读写”)。
请勿将文件读写的当前位置指针与FILE指针、及FILE结构体中的buffer指针相混。
读写方式:
文本方式与二进制方式
任何文件都可以以文本方式或二进制方式打开。
两者在读写文件时的区别是:
文本方式:
当写文件时,如果被写的内存字节是0x0D(‘\r’),它被照写不变,但若是0x0A(‘\n’)
则写两个字节0x0D0x0A(‘\r’‘\n’)到文件上。
反之,当读文件时,凡遇到0x0D时
即‘\r’时就跳过不计,自动移到下一字节(直到非‘\r’),而0x0A(‘\n’)照读不误。
这也顺便说明了为什么printf()遇到‘\n’时不仅在屏幕上换行(‘\n’)而且也回车(这
是‘\r’的功能)。
二进制方式:
与文本方式不同,写时即不转换‘\n’,读时也不滤掉‘\r’,任何字节都原封不动地
写入文件或读到内存。
虽然任何文件的读写方式都可在fopen()时任意指定,但习惯上,一般用文本方式读写文本文件,
即ASCII.txt文件,而用二进制方式读写其他文件。
顺便指出,字节和字符(ASCII)在文件I/O中是一个意思,当说字符时,实际也是指存放该字符
的8-bit字节,或该字符的8-bit编码。
只是,当处理文本文件时,人们习惯用“字符”,而处理
二进制文件时,习惯用术语“字节”。
标准设备文件:
任何TurboC程序开始运行时,都自动打开了5个设备文件,这5个FILE指针变量名(系统变量)是:
stdin标准输入(键盘)文件
stdout标准输出(屏幕)文件
stderr标准出错输出(屏幕)文件
stdprn标准打印(打印机)文件
stdaux标准辅助输入输出(串口)文件
于是,为了读或写上述某文件,你只须直接引用相应的FILE指针变量名(代替Fp)。
关闭文件:
intfclose(FILE*Fp);
本函数关闭已打开的文件Fp,如果关闭成功,本函数返回0,否则返回一个非零值(-1)。
关闭意味着:
a)释放该文件打开时建立的I/0缓冲区,如果在缓冲区中尚有未写入文件中的数据,
在释放前,先写入文件。
B)Fp文件关闭后不能再读写,Fp指向的FILE结构体所占的内存空间也被
释放,Fp置成NULL。
以下介绍主要的读写函数,并以例说明它们的用法。
写一个字符(字节):
intfputc(intc,FILE*Fp);
该函数把int变量c的低8位(也可是char变量)写到Fp文件的当前位置。
该函数的返回值是c的
值或EOF,EOF表示写操作不成功。
另外,宏putc(c,fp)也能用来写字符c,而
#defineputchar(c)putc((c),stdout)
注意,函数fputc(c,Fp)或putc(c,Fp)只是写单个字符或字节到文件的当前位置,写完后当前位置
自动移动到文件的下一字节位置。
于是,你可连续地用这个函数把一串字节顺序写到文件上。
读一个字符(字节):
intfgetc(FILE*Fp);
该函数返回Fp文件当前位置上的那个字节(作为int类型返回值的低8位)。
如果当前位置是EOF
(文件尾),则返回EOF(stdio.h中定义EOF为–1)。
如果用此函数顺序读ASCII文件,你可判断返回值是不是EOF而知文件是否读完(ASCII字符的编码
是0-127,不可能是-1)。
但若读非ASCII文件,值-1可能是文件的正文内容,并不一定意味着文件尾。
因此,你不能用上述方法判断文件是否读完。
但在任何情形,你都能用FILE结构体中的flags值的
第6位(从右数)是否为1知道当前位置是否在文件尾。
等价地,你也可以用宏feof(Fp)来判断:
feof(Fp)==1意味着Fp文件当前在文件尾。
此外,文件读写时也可能出错,你可用flags值的第5位或ferror(Fp)宏判断。
即在任何I/O操作
之后,若ferror(Fp)为1(真),则表示出错。
顺便指出,宏getc(Fp)同效于fgetc(Fp),但getc(Fp)的值是char型的,而getchar()定义为:
#definegetchar()getc(stdin)
类似于fgetc(c,Fp)写的是单个字符,本函数也只是从文件上读单个字符(或字节),如果想读完
整个文件,你必须在打开文件后连续地使用本函数,直至文件尾。
因为每读一个字符后,文件的
当前位置指针自动加1,下一次再读时读的肯定是下一字符,所以你不必自己去移动当前位置指针。
例文件:
Students.txt
姓名系别性身高出生入学
01234
012345678901234567890123456789012345678901234
----------------------------------------
ZhangHaiMathDeptF1.861973082619970915┓
WangJunMathDeptF1.811965092119960131┃
ZhouLingMathDeptM1.611974030119970915┣整个文件内容,共5行
WangJingMathDeptF1.751972052119960214┃
ZhangYunMathDeptM1.711974091119970915┛
---------------------------------------------
每行45个正文字符加上2个字符(\r\n)。
整个文件5行,共47x5=235字符,或233,最后可能
无回车和换行符,依赖于写文件是是否写它们。
注意,数据之间用一个空格符分界。
在以下每一例的程序中,应包含下述语句(例中不再写出):
#include
FILE*fp;
CharFileName[20]=“Students.txt”;
例1.用fputc()函数创建Students.txt文件:
#include
main(){
charStArr[5][47]={
{"ZhangHaiMathDeptF1.861973082619970915\n"},
{"WangJunMathDeptF1.811965092119960131\n"},
{"ZhouLingMathDeptM1.611974030119970915\n"},
{"WangJingMathDeptF1.751972052119960214\n"},
{"ZhangYunMathDeptM1.711974091119970915\n"}};
/*Note:
AtArr[i][45]=’\n’,StArr[i][46]=’\0’(初始化时自动补\0)*/
inti,k;charc;
fp=fopen(FileName,“w”);/*建新文件,Textmode*/
/*如果Binarymode“wb”,初值中的\n应当换成\r\n,StArr[5][48]。
其他语句均不变。
*/
if(fp==NULL)
{printf("Cannotcreatethenewfile.\n");
exit(0);}
for(i=0;i<5;i++)
for(k=0;(c=StArr[i][k])!
='\0';k++)
fputc(c,fp);/*写StArr[i][k]*/
if(fclose(fp)!
=0)/*关闭文件,成功时为0*/
printf("Cannotclosethefile.\n");
else
printf(“\n%s”,strcat(FileName,"wascreated."));
}
例2.用fgetc()函数读Students.txt文件:
本例把Students.txt文件的第i行(以\n结尾)读到StArr数组的第i行StArr[i]中,且补’\0’。
main(){
charStArr[100][50];
inti,k;charc;
fp=fopen(FileName,“r”);/*读文件,Textmode*/
/*在Textmode,文件中的\r\n读成\n*/
/*如果Binarymode“rb”,文件中任何字符均不变地被读入。
*/
i=0;k=0;
while((c=fgetc(fp))!
=EOF&&i<100)
{StArr[i][k]=c;/*读入StArr[i][k]*/
k++;
if(c=='\n'){StArr[i][k]='\0';i++;k=0;}/*行尾补\0*/
}
fclose(fp);/*关闭文件*/
}
写一串字符(字节):
intfputs(char*s,FILE*Fp);
该函数把以‘\0’结尾的字符串s写到Fp文件中,从当前位置开始。
但最后的‘\0’不写。
写成功时返回写入的最后字符,出错时返回EOF。
读一串字符(字节):
char*fgets(char*s,intn,FILE*Fp);
该函数把Fp文件当前位置开始的(至多)n-1个字符读到字符数组s中,如果遇到‘\r’,则跳过
不计它。
但若遇到‘\n’,即使还不到n-1个,则在把‘\n’读到s中后,也不再读了。
最后在s中
补上‘\0’后,fgets()返回,返回值也是指向s的指针。
如果在上述读的过程中,发生错误或先
遇到文件尾,则返回NULL–此时你须用feof(Fp)或ferror(Fp)才能判断是遇到文件尾还是出错。
例3.用fputs()函数创建Students.txt文件:
main(){
charStArr[5][47]={。
。
。
};/*初始化同例1*/
inti;
fp=fopen(FileName,“w”);/*建新文件,Textmode*/
/*如果Binarymode“wb”,初值中的\n应当换成\r\n,StArr[5][48]。
其他语句均不变。
*/
for(i=0;i<5;i++)
fputs(StArr[i],fp);/*写StArr[i]*/
fclose(fp)/*关闭文件*/
}
例4.用fgets()函数读Students.txt文件:
charStArr[100][50];
fp=fopen(FileName,“r”);/*读文件,Textmode*/
i=0;
while(fgets(StArr[i],50,fp)!
=NULL&&i<100)i++;
/*读每一行(以\n结尾),自动补\0*/
fclose(fp);/*关闭文件*/
写mxn个字节(字符):
typedefunsignedsize_t;
size_tfwrite(constvoid*ptr,size_tm,size_tn,FILE*Fp);
本函数把从ptr(可以是任何基类型的指针)指向的内存地址开始的m*n个字符(字节)写入Fp文
件,从文件当前位置开始。
每m个字符(字节)视为一个“记录”。
于是,本函数共写n个记录。
函数返回的值是实际写的记录数,正常时就是n。
但如果在写的过程出错,返回值就会比n小了。
读mxn个字节(字符):
size_tfread(void*ptr,size_tm,size_tn,FILE*Fp);
本函数从文件当前位置开始,读m*n个字节,放到由ptr地址开始的内存区。
每m个字节视为一个
“记录”。
于是,本函数共读n个记录。
函数返回的值是实际读的记录数,正常时就是n。
但如果在
读的过程出错,或先遇到文件尾,返回值就会比n小了。
此时你可用feof(Fp)或ferror(Fp)判断
原因。
注:
fwrite()常常用于一次写一个结构体变量的值或写结构体数组的多个元素,m=sizeof(结构体类型),
n>=1。
每一个结构体相当于一个“记录”。
用fwrite()写到文件上的数据通常可以用fread()读
回来。
例5.用fwrite()函数创建Students.dat文件(Binary):
Students.txt是ASCII文件,但在程序中,学生的身高通常用浮点数类型,以便用于计算,如
计算学生的平均身高等。
显然,用Struct类型来描述学生的信息是合理的。
我们将从Students.txt文件读出学生信息,并把字符形式的身高转换为float形式。
然后,再
用fwrite()输出,创建Students.dat二进制文件。
最后再用fread()读出,并check结果。
#include
#include
#include
FILE*fp;
charFileName1[20]={"Students.txt"};charFileName2[20]={"Students.dat"};
structSTUD
{charStName[11],DeptName[10];charSex;
floatHeight;charBornDate[9],EntryDate[9];};
typedefstructSTUDSTUDENT;
main()
{STUDENTSt[100];charSS[50];inti,n;
externSTUDENT*ssTOst(char*,STUDENT*);
fp=fopen(FileName1,"r");n=0;
while((fgets(SS,50,fp))!
=NULL&&n<100)/*读.txt文件*/
{ssTOst(SS,&St[n]);n++;}/*转换成STUDENT结构体*/
fclose(fp);/*txt文件共n行*/
fp=fopen(FileName2,"w+b");/*CreateOpeninBinaryR/Wmode*/
fwrite(St,sizeof(STUDENT),n,fp);/*写St[]到BinaryFile,用sizeop(struct)*/
fflush(fp);/*清buffer*/
rewind(fp);/*pointtotop*/
fread(St,sizeof(STUDENT),n,fp);/*读BinaryFile到St[]*/
fclose(fp);
for(i=0;i */ printf("%s%s%c%4.2f%s%s\n",St[i].StName,St[i].DeptName, St[i].Sex,St[i].Height,St[i].BornDate,St[i].EntryDate); }/*endofmain()*/ char*substr(char*dest,char*str,intbegin,intn)/*截取str的子串*/ {inti;charc;begin=begin-1; for(i=0;i ='\0')*(dest+i)=c;elsebreak; *(dest+i)='\0';returndest;} STUDENT*ssTOst(charss[],STUDENT*st)/*把一行字符的学生信息转换为STUDENT结构体: */ {chars1[11]; strcpy(st->StName,substr(s1,ss,1,10));strcpy(st->DeptName,substr(s1,ss,12,9)); st->Sex=ss[21];st->Height=(float)atof(substr(s1,ss,24,4));/*数字串=>数*/ strc
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 语言 文件 存取