c语言中文件的操作

来源:互联网 发布:最新淘宝浏览单app 编辑:程序博客网 时间:2024/05/18 03:23
C语言中文件的操作(上)

C语言的文件以字节为单位,即以字节为单位进行读写。

 

C的文件类型分为两类:ASCII文件和二进制文件,ASCII文件又称为文本件。二进制文件则称为非文本文件。

例如:数据10000的表示形式分别如下。

在内存中存储形式:

00100111   00010000 

在磁盘中的存储形式:
ASCII形式(文本文件):

00110001  00110000  00110000  00110000
    (1)             (0)            (0)           (0)
 
二进制格式(非文本文件) 

00100111 00010000 


缓冲文件系统
  缓冲文件系统是指:系统在内存区自动为每一个正在使用的文件开辟一个缓冲区,它的大小由C的版本确定,一般为512Byte。内存与磁盘空间的数据交换都必须经过缓冲区,而且必须充满缓冲区(文件结束时可以不要求)。

非缓冲区文件系统
 非缓冲区文件系统:系统不自动开辟缓冲区的大小,而由程序为每一个文件设订缓冲区。这种处理方式为早期的C语言采用。

打开文件函数-- fopen( )函数的调用方式:

FILE *fp;
fp=fopen(文件名,使用文件方式);

该函数执行后将打开一个文件。参数中文件名即是要打开的文件的名称,使用文件的方式即是读写的方式,使用方式下表,fp则是指向正要打开的文件。fopen函数带回指向文件的指针赋给fp,这样fp和文件相连系了。
 
文件使用方式                         含义                                    
   “r” (只读)              为输入打开一个文本文件
   “w” (只写)            为输出打开一个文本文件   
   “a” (追加)              向文本文件尾增加数据
   “rb” (只读)            为输入打开一个二进制文件
   “wb” (只写)           为输出打开一个二进制文件
   “ab” (追加)            向二进制文件尾增加数据
    “r+” (读写)           为读/写打开一个文本文件
    “w+” (读写)         为读/写建立一个新的文本文件
    “a+” (读写)          为读/写打开一个文本文件 
    “rb+” (读写)         为读/写打开一个二进制文件
    “wb+” (读写)        为读/写建立一个新的二进制文件
    “ab+” (读写)         为读/写打开一个二进制文件

说明:

(1) 用r(只读)方式打开文件只能用于程序从文件输入数据,不能向文件输出数据,而且要求该文件已经存在,否则函数fopen()将返回空指针NULL。
(2) 用w(只写)方式打开的文件只能用于向文件输出数据,不能从该文件中输入数据,如果打开时原文件不存在,则新建该文件,如果原文件已经存在,则删除原文件里的数据。
(3)用a(追加)方式打开的文件,表示不删除原文件里的数据,而是从文件的末尾开始填加数据,要求被打开的文件已经存在,打开后,文件的位置指针将定位在文件的末尾,如果打开的文件已经存在,则函数fopen()返回一个空指针。
(4)用r+, w+,a+(读/写)方式打开的文件,既可以从文件输入数据,也可以向文件输出数据,其中r+只允许打开已存在的文件,用w+方式打开,则系统新建一个文件,先向文件输出数据,然后才能从文件中输入数据。用a+方式是打开已经存在的文件,并且文件的位置指针定位在文件的末尾,先准备向文件添加数据,以后也可以从文件中输入数据。
(5)上述打开的文件都是针对文本文件,如果要打开二进制文件,必须在使用方式后面添上字符b,如rb表示以只读方式打开一个二进制文件。

使用打开函数时需要注意以下几点: 
1.读写文件函数的使用与文件的打开方式必须相匹配。
2.用文本文件的计算机输入时,将回车换行符转为一个换行符,在输出时把换行符按原样转换回去。
3.在程序运行时,系统自动打开三个标准文件:标准输入、标准输出、标准出错输出。

关闭文件函数-- fclose( )函数的调用方式: 
FILE *fp;
fclose(fp);

fclose()的作用是使文件指针变量撤消原先调用fopen()函数时所建立的它与文件的联系。

 

C语言中文件的操作(下)

文件的读写

 

文件被打开后,立即可以执行读写操作.在下面的函数中所应用的fp是指文件指针变量,它从fopen( )函数得到返回值,在下面使用fp之处,不再另加说明.

测试文件尾函数--feof( )函数

调用方式: feof(fp) 该函数用来测试fp所指向的文件的当前状态: 文件结束,函数值为1 否则值为0

读写一个字符函数--函数fgetc()和fputc()

调用形式分别为: ch=fgetc(fp); fputc(ch,fp); fgetc()函数将fp指向的文件的一个字符读到内存,赋给字符变量ch.如果遇文件结束符时,函数返回值为1. 为便于书写,在stdio.h中将fgetc()和fputc()定义宏名为getc()和putc():
#define getc(fp) fgetc(fp)
#define putc(ch,fp) fputc(ch,fp) 
例:从键盘输入一些字符逐个送入磁盘,直到#为止。再将此盘文件读入内存,逐个显示在光屏。 

# include "stdio.h"
main( ) 
{FILE *fp;
char ch,filename[10]; 
scanf("%s",filename); /*读入磁盘文件名*/
if((fp=fopen(filename,"w"))==NULL) /*建立新文件 */
{ printf("cannot open file/n"); /*建立新文件出错误信息*/
exit(1); /*终止调用过程、关闭所有文件*/

ch=getchar( ); /*从键盘读入一个字符*/
while(ch!='#') /*读到#时停止输入*/
{ fputc(ch,fp); /*将ch内字符写入fp指向的文件*/
ch=getchar( );
}
close(fp); /*关闭fp所指向的文件*/
if((fp=fopen(filename,"r"))==NULL) /*将filename 以'r'方式打开*/
{printf("cannot open file/n"); 
exit (1);

ch=fgetc(fp); /*从fp指向的文件读一个字符给ch变量 */
while(ch!=EOF) /*读到文件结束符EOF时结束 */
{putchar(ch);
ch=fgetc(fp);
}
fclose(fp); /*关闭文件*/
}

请你运行程序,按如下的输入,可以得到如下的结果:
file.c basic、fortran and c
computer #
basic、fortran and c 
computer

用DOS命令TYPE检查file.c的内容:
C:>TYPE file.c
basic、fortran and c
computer 

读写数据块函数--fread( )和fwrite( )函数 

调用方式分别为: fread(buffer,size,count,fp); 
该函数将fp指向的文件的数据以数据块的形式读入内存buffer。
fwrite(buffer,size,count,fp);
该函数将内存buffer的内容以数据块的形式写入fp指向的文件。 其中: buffer:是一个指针。对于fread来说 它是读入数据的有效地址。对 fwrite来说,是要写盘的数据地址(起始地址)。 size:要读写的字节数。 count:要进行读写多少个size字节的 数据项。 fp:文件型指针 如果fread或fwrite调用成功,则函数返回值为count的值。 若文件以二进制形式打开,用fread和fwrite函数就可以读写任何类型的信息。如: fread(f,4,2,fp); f为实型数组名,4表示个实型变量占4个字节,2表示读入2次,fp向的文件数据. 
例:从键盘输入4个学生的有关数据,然后把它们转存到磁盘文件上去。

 

#include"stdio.h"
#define SIZE 4 
struct student_type
{char name[10];
int num;
int age;
char addr[15];
}stud[SIZE];

void save() /*save( )函数,将数据送到"stu_list"磁盘文件中去。*/
{FILE *fp;
int i;
if((fp=fopen("stu_list","wb"))==NULL)
{printf("cannot open file/n");
return; 
}
for(i=0;i<SIZE;i++)
if(fwrite(&stud[i],sizeof(struct student_type),1,fp)!=1)
/*函数sizeof 计算一个结构体student_type的变量长度29(10+2+2+15)字节*/
printf("file write error/n");
}

main() /*在主函数main( )中的终端读入4个学生的数据,然后调用save( )函数。*/
{int i;
for(i=0;i<SIZE;i++)
scanf("%s%d%d%s",stud[i].name,&stud[i].num,&stud[i].age, stud[i].addr);
save();
}

运行情况如下。
输入4个学生的姓名、学号、年龄和地址:
zhang 1001 17 room-101
fun 1002 18 room-102
tan 1003 19 room-103
ling 1004 20 room-104 

好了,数据已经存入文件中了.如何验证呢?请看例:


验证上例读入的磁盘文件"stu_list"数据是否正确,将该盘文件读入内存,并从荧屏上显示。 

#include"stdio.h" 
#define SIZE 4
struct student_type 
{char name[10];
int num;
int age;
char addr[15];
}stud[SIZE];

main( )
{int i;
FILE *fp;
fp=fopen("stu_list","rb");
for(i=0;i<SIZE;i++)
{fread(&stud[i],sizeof(struct student_type),1,fp);
printf("%-10s%4d%4d%-l5s/n",stud[i].name, stud[i].num,stud[i].age,stud[i].addr);
}
}

程序运行时,屏幕将显示出以下信息:
zhang 1001 17 room-101
fun 1002 18 room-102 
tan 1003 19 room-103
ling 1004 20 room-104 

正是上例存入的数据.

程序注释:
原始数据以ASCII 形式输入到内存时,回车换行符换成一个换行符。以"wb"方式从内存写到文件"stu_list",以及再以"rb"方式将"stu_list"文件读入内存,其间都不发生字符转换。当用printf函数输出到屏幕时以ASCII 形式输出,换行符又转换为回车加换行符。

格式化读写函数--fscanf( )函数和fprint( )函数 

调用方式分别是: fscanf(文件指针,格式字符串,输入表);
fscanf 函数将指针指向的文件内容,以格式符要求的形式,读入内存指定地址内 fprintf(文件指针,格式字符串,输出表);fprintf 函数是将内存指定地址内的内容,以格式符要求的形式,输出到指针指向的文件 

说明: 以上两个函数与scanf( ) 和printf( )函数 只有一点不同:即前二者的读写对象是磁盘数据文件,即是文件指针指向的磁盘文件。 用fscanf( )和fprintf( )函数对磁盘文件 进行读写,使用方便,容易理解,但是,由于输入是要将ASCII码转换为二进制形式,输出时又要将二进制形式转换成字符,花费时间较多。因此,在内存与磁盘频繁交换数据的情况下,最好不用fscanf( )和fprintf( )函数,而用fread和fwrite函数。 


例:编制一个程序,建立一个电话簿,包括姓名和电话号码两项内容,该程序有增加新姓名和电话号码的功能,也可以根据姓名查询已经存入电话簿的电话号码。

程序在设计时将分别设计成三个函数:

1.菜单选项--menu( )
2.增加新电话号码--add-num( )
3.查询老电话号码--lookup( )。

程序如下:

#include "stdio.h" 
void add_num( ),lookup( );

main( )
{ char choice;
do{choice=menu( ); 
switch(choice)
{ case 'A':add_num( ); break;
case 'L':lookup( ); break; }
}while(choice!='Q');
}

menu( )
{ char ch;
do{ 
printf("(A)dd,(L)ookup or (Q)uit:"); 
ch=tolower(getche( ));
printf("/n"); }
while(ch!='Q'&&ch!='A'&&ch!='L');
return ch;
}

void add_num( )
{ FILE * fp;
char name[80];
int a_code,exchg,num;
if((fp=fopen("phone","a"))==NULL)
{ printf("cannot open directory file/n"); exit(1); }
printf("enter name and number:");
fscanf(stdin,"%s%d%d%d",name,&a_code,&exchg,&num);
fscanf(stdin,"%*c"); 
fprintf(fp,"%s %d %d %d n",name,a_code,exchg,num);
fclose(fp);
}

void lookup( )
{ FILE *fp;
char name[80],name2[80];
int a_code,exchg,num;
if((fp=fopen("phone","r"))==NULL) 
{ printf("cannot open directory file/n"); exit(1); }
printf("name?");
gets(name);
while(!feof(fp)) 
{fscanf(fp,"%s%d%d%d",name2,&a_code,&exchg,&num);
if(!strcmp(name,name2)) 
{printf("%s: (%d)%d-%d/n",name,a_code,exchg,num); break; }
}
fclose(fp);
}

请运行程序,可以得到如下结果:

(A)dd,(L)ookup or (Q)uit:A Enter name and number: Liming 6789 1234 135
(A)dd,(L)ookup or (Q)uit:A Enter name and number: Lihung 5678 235 357
(A)dd,(L)ookup or (Q)uit:L name?Liming Liming:(6789)1234-135 
(A)dd,(L)ookup or (Q)uit:Q 

读入整型量函数--- getw( )函数和putw( )函数

调用方式如下例:
i=getw(fp);
它的作用是从磁盘文件读一个整数到内存,赋给整型变量i。
putw(10,fp);
它的作用是将整数10输出到fp指向的文件。

读写字符串函数-- fgets( )函数和fputs( )函数

调用方式分别为:
fgets(字符数组,n,fp);
fgets( )函数的作用是将fp指向的文件中
(n-1)个字符读入字符数组,并且加结束符“/0”,若在(n-1) 个字符前遇到EOF或换行符,均结束读入。
fputs(字符数组,fp);
fputs( )函数的作用是向指定的文件输出一个字符串。如:
fputs(“china”,fp);

说明:
fgets( )和fputs( )函数与gets( )和puts( )函数的不同之处也在于:
前二者的读写对象为指定的文件。

 用户自定义读写函数

如果用户对于读写盘文件还有特殊的要求,或者是在某些C编译的库函数中,不包括前面所介绍的那些读写函数,用户也可以自己定义函数。

比如:

定义getw函数
getw(fp)
FILE *fp;
{char *s; int i;
s=&i;
s[0]=getc(fp); s[1]=getc(fp);
return(i);

定义putw函数
putw(i,fp)
int i;
FILE *fp;
{char *s;
s=&i;
putc(s[0],fp);putc(s[1],fp);
return(i);
}

文件中有一个位置指针,指向当前的读写的位置。文件位置指针和指向文件的指针是两个不同的概念,读者必须要加以区分。位置指针随读写的进行而移动,由移动方式确定了两类读写:顺序读写与随机读写。如果位置指针按字节顺序移动,就是顺序读写。如果可以将位置指针按须要移动到任意位置,则可以实现随机读写。位置指针的当前位置用相对于文件开头的位移量表示。掌握当前位置指针情况,对读写的进行非常重要。

文件输入输出函数一览表 

分类                  函数名                 功能 
打开文件         
                      fopen( )             打开文件。
关闭文件       
                      fclose( )             关闭文件。                           
                      exit( )                退出程序功能。 
文件定位        
                     fseek( )              改变文件位置指针位置。
                     rewind( )            使文件位置指针重新置于文件开头。 
                     ftell( )                返回文件位置指针的当前值。
文件读写         
                     fgetc( ),getc( )   从指定文件取得一个字符。
                     fputc( ),putc( )   把字符输出到指定文件。
                     fgets( )              从指定文件读取字符串。
                     fputs( )              把字符串输出到指定文件。 
                     getw( )             从指定文件读取一个字(int型)。
                     putw( )             把一个字(int型)输出到指定文件。 
                     fread( )             从指定文件中读取数据项。
                     fwrite( )            把数据项写到指定文件。
                     fscanf( )            从指定文件按格式输入数据。
                     fprintf( )            按指定格式将数据写到指定文件中。 
文件状态         
                     feof( )              若到文件末尾,函数值为“真”(非0)。 
                     ferror( )         若对文件操作出错,函数值为“真”(非0)。
                     clearerr( )       使ferror和feof函数值置零。

常见的文件读、写错误 

1. 使用文件时忘记打开文件。用后又忘记关闭文件,造成文件的数据丢失。
2. 混淆文件指针与文件读/写的位置指针的概念。
3. 不明确当前位置指针的位置,造成读/写错误。
4. 不能使文件正确定位。
5. 文件的打开与使用方式不匹配。
例如,对文件以只读方式打开,却对文件进行读写,请看程序:

if((fp=fopen(“test”,“r”))==NULL)
{printf(“cannot open this file/n”);
exit(1);
}
ch=fget(fp);
while(ch!=‘#’)
{ch=ch+4;
fputc(ch,fp);
ch=fget(fp);
}

以上程序段的“r”应改作“r+”。

1、fscanf函数只能从文本文件中按格式输入。fscanf函数和scanf函数相似,只是输入的对象是磁盘上文本文件中的数据。函数的调用形式如下:fscanf(文件指针,格式控制字符串,输入项表)例如,若文件指针fp已指向一个已打开的文本文件,a、b分别为整型变量,则以下语句从fp所指的文件中读入两个整数放入变量a和b中:fscanf(fp, "%d%d",&a,&b);注意:文件中的两个整数之间用空格(或跳格符、回车符)隔开。语句:fscanf(stdin,"%d%d",&a,&b);等价于:scanf("%d%d",&a,&b);因为文件名stdin就是代表终端键盘。

       2、fprintf函数按格式将内存中的数据转换成对应的字符,并以ASCⅡ代码形式输出到文本文件中。fprintf函数和printf函数相似,只是输出的内容将按格式存放在磁盘的文本文件中。函数的调用形式如下:fprintf(文件指针,格式控制字符串,输出项表)例如,若文件指针fp已指向一个已打开的文本文件,x,y分别为整型变量,则以下语句将把x和y两个整型变量中的整数按%d格式输出到fp所指的文件中:fprintf(fp,“%d %d”,x,y);注意:为了以后便于读入,两个数之间应当用空格隔开。同时也是为了便于读入,最好不要输出附加的其他字符串。以下语句:fprintf(stdout,“%d %d”,x,y);等价于:printf(”%d %d”,x,y);因为文件名stdout就是代表终端屏幕。

       3、 fprintf和fscanf函数对磁盘文件读写,使用方便,但由于在输入时要将ASCII码转换为二进制形式,在输出时又要将二进制形式转换为字符,花费时间比较多。因此,在内存与磁盘频繁交换数据的情况下,最好不用fprinf和fscanf函数,而用fread和fwrite。

 fscanf函数从一个流中执行格式化输入,fscanf遇到空格和换行时结束,注意空格时也结束。这与fgets有区别,fgets遇到空格不结束。

原型:int fscanf(FILE *stream, char *format,[argument...]);

返回值:返回实际被转换并赋值的输入项的数目。

  %d:读入一个十进制整数。

  %i :读入十进制,八进制,十六进制整数,与%d类似,但是在编译时通过数据前置来区分进制,如加入“0x”则是十六进制,加入“0”则为八进制。例如串“031”使用%d时会被算作31,但是使用%i时会算作25。


scanf(...)函数与fscanf(stdin,...)相同。

sscanf(s,...)函数与scanf(...)等价,所不同的是,前者的输入字符来源于字符串s.

------------------------------------------

下面是百科中的两个DEMO

------------------------------------------


[cpp] view plaincopy
  1. /************************************************************************/  
  2. /* fscanf函数DEMO 
  3. */  
  4. /************************************************************************/  
  5.   
  6.   
  7. #include <stdio.h>  
  8. #include <stdlib.h>  
  9. #define FIRST_DEMO  
  10. //#define SECOND_DEMO  
  11. #ifdef FIRST_DEMO  
  12. int main(void)  
  13. {  
  14.     int i;  
  15.     printf("Input an integer:");  
  16.     /*read an integer from the standard input stream*/  
  17.     if (fscanf(stdin,"%d",&i))  
  18.     {  
  19.         printf("The integer read was :%d\n",i);  
  20.     }   
  21.     else  
  22.     {  
  23.         fprintf(stderr,"Error reading an integer from stdin.\n");  
  24.         exit(1);  
  25.     }  
  26.     system("pause");  
  27.     return 0;  
  28. }  
  29. #elif defined SECOND_DEMO  
  30.     FILE *stream;  
  31.     int main(void)  
  32.     {  
  33.         long l;  
  34.         float fp;  
  35.         char s[81];  
  36.         char c;  
  37.         stream=fopen("fscanf.out","w+");  
  38.         if (stream == NULL)  
  39.         {  
  40.             printf("The file fscanf.out was not opened.\n");  
  41.         }   
  42.         else  
  43.         {  
  44.             fprintf(stream,"%s %ld %f%c","a-string",65000,3.14159,'x');   //%c前没有空格  
  45.             /*set pointer to beginning of file*/  
  46.             fseek(stream,0L,SEEK_SET);  
  47.             /*Read data back from file*/  
  48.             fscanf(stream,"%s",s);  
  49.             fscanf(stream,"%ld",&l);  
  50.             fscanf(stream,"%f",&fp);  
  51.             fscanf(stream,"%c",&c);  
  52.             /*output data read*/  
  53.             printf("%s\n",s);  
  54.             printf("%ld\n",l);  
  55.             printf("%f\n",fp);  
  56.             printf("c=%c\n",c);  
  57.             fclose(stream);  
  58.         }  
  59.         system("pause");  
  60.         return 0;  
  61.     }  
  62.   
  63. #endif  
  64. 补充:http://www.cnblogs.com/likebeta/archive/2012/06/16/2551662.html


0 0