logo.gif (2828 bytes)
logo1.gif (253 bytes)
pageup.jpg (7897 bytes)firstpage.jpg (7734 bytes)pagedown.jpg (7767 bytes)

第十章 文件

§10.1 C文件概述

所谓"文件"一般指:存储在外部介质上的数据的集合。一批数据是以文件的形式存放在外部介质(如磁盘)上的。

§10.2 文件类型指针

在缓冲文件系统中,关键的概念是"文件指针"。每个被使用的文件都在内存中开辟一个区域,用来存放文件的有关信息(如文件名字、文件的状态以及文件的当前位置等)。这些信息是保存在一个结构体类型的变量中的。该结构体类型是由系统定义的,取名为FILE。有的C版本在stdio.h文件中有以下类型的定义:

typedef struct

{

int -fd; /* 文件号 */

int -cleft; /* 缓冲区中剩下的字符 */

int -mode; /* 文件的操作模式 */

char *-nextc; /* 下一个字符的位置 */

char *-buff; /* 文件的缓冲区的位置 */

}FILE;

有了FILE类型之后,可以用它来定义若干个FILE类型的变量,以便存放若干个文件的信息。例如,可以定义文件类型的指针变量。如:

FILE *fp;

fp是一个指向FILE类型结构体的指针变量。可以使fp指向某一个文件的结构体变量,从而通过该结构体中的文件信息能够访问该文件。

 

§10.3 文件的打开和关闭

和其它高级语言,对文件读写之前应该"打开"文件,在使用结束之后应"关闭"该文件。

10.3.1 文件的打开(fopen函数)

ANSI C 规定了标准输入输出函数库,用fopen()函数来实现打开文件。

fopen()函数的调用方式通常为:

FILE *fp;

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

例如:

fp=("d:\\aa.txt", "r");

使用文件的方式见表10.1

文件使用方式

"r" (只读)

为输入打开一个文本文件

"w" (只写)

为输出打开一个文本文件

"a" (追加)

向文本文件尾增加数据

"rb" (只读)

为输入打开一个二进制文件

"wb” (只写)

为输出打开一个二进制文件

"ab" (追加)

向二进制文件尾增加数据

"r+" (读写)

为读/写打开一个文本文件

"w+" (读写)

为读/写建立一个新的文本文件

"a+" (读写)

为读/写打开一个文本文件

"rb+" (读写)

为读/写打开一个二进制文件

"wb+" (读写)

为读/写建立一个新的二进制文件

"ab+" (读写)

为读/写打开一个二进制文件

                              10.1

说明:

1. "r"方式打开的文件只能用于向计算机输入而不能用于向该文件输出数据,而且该文件应该已经存在,不能打开一个并不存在的用于"r"方式的文件(即输入文件),否则出错。

2. "w"方式打开的文件只能用于向该文件写数据,而不能用来向计算机输入。如果原来不存在的文件,则在打开时新建一个以指定名字命名的文件。如果原来已经存在一个以该文件名命名的,则在打开时将该文件删除,重新建立一个新文件。

3. 如果希望向文件末尾添加新数据,用"a"方式打开,但此时文件必须存在,否则将出现出错信息。打开时位置指针移到文件末尾。

4. "r+"方式时该文件已经存在,以便能向计算机输入数据。 "w+"方式则建立一个文件,先向文件写数据,然后可以读此文件中的数据。

5. 如果不能实现"打开"的任务,fopen函数将会带回一个出错信息,此时fopen函数将会带回一个空指针值NULL。常用下面的方法打开一个文件:

if ((fp = fopen("file1", " r "))= =NULL)

{ printf ("cannot open this file\n ");

exit(0);

} 即先检查是否出错,如果有错就在终端上输出"cannot open this file"exit函数的作用是关闭所有文件,终止正调用过程。待程序员检查出错误,修改后再运行。

6. 用以上方式可以打开文本文件或二进制文件,用同一种缓冲文件系统来处理文本文件和二进制文件。

7. 在用文本文件向计算机输入时,将回车换行符转换为一个换行符,在输出时把换行符转换为回车和换行两个字符。在用二进制文件时,不进行这种转换。

8. 在程序开始运行时,系统自动打开三个标准文件:标准输入、标准输出、标准出错输出。通常这三个文件都与终端相联系。系统自动定义了三个 文件指针stdinstdoutstderr分别指向终端输入、终端输出、标准出错输出。如果在程序中指定要从stdin所指的文件输入数据,就是指从终端键盘输入数据。

10.3.1 文件的关闭(fclose函数)

在使用完一个文件后应该关闭它。"关闭"就是使文件指针变量不指向该文件,此后不能再通过该指针对其相连的文件进行读写操作,除非再次打开,使该指针变量重新指向该文件。用fclose函数关闭文件。

fclose函数调用的一般形式为:

 fclose(文件指针);

例如:fclose(fp);

 

§10.4 文件的读写

10.4.1 fputc函数和fgetc函数

一、 fputc函数把一个字符写到磁盘文件中去。

其一般形式为: fputc(ch,fp);

二、fgetc函数从指定文件读入一个字符,该文件必须是以读或读写方式打开的。

fgetc函数的调用形式为:

ch = fgetc(fp);

如果想从一个磁盘文件顺序读入字符并在屏幕上显示出来可以:

ch = fgetc(fp);

while(ch! = EOF)

{

putcher( ch );

ch = fgetc(fp);

}

注意:EOF不是可输出字符,因此不能在屏幕上显示。

如果想顺序读入一个二进制文件中的数据,可以用:

while( !feof (fp) )

{ c = fgetc(fp);

}

当未遇文件结束,feof(fp)的值为0。!feof(fp)的值为1,这种方法也适用于文本文件。

 

三、fputc函数和fgetc函数使用举例

例:从键盘输入一些字符,逐个把它们送到键盘上去,直到输入一个"#"为止。

#include <stdio.h >

void main(void)

{FILE *fp;

char ch,filename[10];

scanf("%s ",filename);

if ((fp = fopen ( filename, "w ")) = =NULL)

{

printf("cannot open file\n ");
exit(0);

}

ch = getchar( );
while (ch!= ’#’)

{

fputc(ch,fp);

putchar(ch);

ch=getchar( );

}

fclose(fp);

}

运行情况如下:file1.c (输入磁盘文件名)

computer and c# (输入一个字符串)

computer and c (输入一个字符串)

本例运行时,从键盘输入磁盘文件名"file1.c",然后输入要写入该磁盘文件的字符"computer and c",同时在屏幕上显示这些字符。

 

12.4.2 fread函数和fwrite函数

getcputc函数可以用来读写文件中的一个字符。但是常常要求一次读入一组数据。

 fread函数和fwrite函数可以用来读写一个数据块。

它们一般调用形式为:

fread (buffer,size,count,fp);

fwrite(buffer,size,count,fp);

buffer:是一个指针。对fread它是读入数据的存放地址。对fwrite是输出数据的地址。

size:要读写的字节数。

count:要进行读写多少个size字节的数据项。

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( void)

{ FILE *fp;

int i;

if ((fp=fopen("stu_list","wb"))= =NULL)

{

print("cannot open file\n");

return;

}

for(i=0;i<SIZE;i++)

if(fwrite(&stud[i],sizeof(struct student_type),1,fp)!=1)

printf("file write error\n");

}

void main(void)

{ 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( );

}

10.4.3 fprintf函数和fscanf函数

fprintf函数和fscanf函数与 printf函数、scanf 函数相仿,都是格式化读写函数。只有一点不同:fprintf函数和fscanf函数的读写对象不是终端而是磁盘文件。一般调用方式为:

fprintf(文件指针,格式字符串,输出表列);

fscanf(文件指针,格式字符串,输入表列);

例如: fprintf(fp"%d,%6.2f"i,t);它的作用是将整型变量i和实型变量t的值按%d%6.2f的格式输出到fp指向的文件上。如果 i=3,t=4.5,则输出到磁盘文件上的是以下的字符串:

34.50

同样,用以下fscanf 函数可以从磁盘文件上读入ASCⅡ字符:fscanf(fp"%d,%f"&i,&t);

这样将磁盘文件中的数据送给变量i,t

 

10.4.4 其它读写函数

一、putw函数和getw函数

这两个函数用来对磁盘文件读写一个字。

例如 putw(10,fp)的作用是将整数10输出到fp 指向的文件。

i=getw(fp); 的作用是从磁盘文件读一个整数到内存,赋给整型变量i

 

二、fgets函数和fputs函数

fgets函数的作用是从指定文件读入一个字符串。

如:fgets(str,n,fp);

fp指向的文件输入n-1个字符,并把它们放到字符数组str中。如果在读入 n-1个字符结束之前遇到换行符或EOF,读入即结束。字符串读入后在最后加一个’\0’字符,fgets 函数的返回值是str的首地址。

fputs函数的作用是从指定文件输出一个字符串。

如:fputs("China",fp);把字符串"China"输出到fp指向的文件,fputs函数中第一个参数可以是字符串常量、字符数组名或字符型指针。输出成功函数值为0;失败时为非零值。

 

§10.5 文件的定位

10.5.1 rewind函数

rewind函数的作用是使位置指针重新返回文件的开头。

此函数没有返回值。

 

例:有一个磁盘文件,第一次使它显示在屏幕上,第二次把它复制到另一文件上。

#include <stdio.h>

void main(void)

{ FILE *fp1,*fp2;

fp1 = fopen("file1.c","r");

fp2 = fopen("file2.c","w");

while(!feof(fp1)) putchar(getc(fp1));

rewind(fp1);

while(!feof(p1)) putc(getc(fp1),fp2);

fclose(fp1);

fclose(fp2);

}

在第一次显示在屏幕以后,文件file1.c的位置指针已指到文件末尾,feof的值为真,执行 rewind 函数,使文件的位置指针重新定位于文件开头,并使feof函数的值恢复为假。

 

10.5.2 fseek函数和随机读写

    如果位置指针是按字节位置顺序移动的,就是顺序读写。如果可以将位置指针按需要移动到他、任意位置,就可以实现随机读写。所谓随机读写是指读完上一个字符后,并不一定要读写其后续的字符,而可以读写文件中任意所需的字符。

    fseek函数可以实现改变文件的位置指针。

    fseek函数的调用形式为

fseek(文件类型指针,位移量,起始点)

起始点用012代替,0代表文件开始1当前位置2文件末尾

位移量指以起始点为基点,向前移动的字节数。一般要求位移量是long型数据。

下面是fseek函数调用的几个例子:

fseek(fp,100L,0); 将位置指针移到离文件头100个字节处。

fseek(fp,50L,1); 将位置指针移到离当前位置50个字节处。

fseek(fp,-10L,2); 将位置指针从文件末尾处向后退10个字节。

 

10.5.3 ftell函数

ftell函数的作用是得到文件的当前位置,如果ftell函数返回值为-1L,表示出错。