关键字:

普通文件、设备文件;

文件文件、二进制文件;

流式文件

FILE *、

字符读写、串读写、块读写、格式化读写。

换行符,EOF,串结束符

随机读写

 


 

文件的基本概念

"文件"是指一组相关数据的有序集合。文件通常是驻留在外部介质(如磁盘等)上的, 在使用时才调入内存中来。从不同的角度可对文件作不同的分类。

 

从用户的角度看,分为普通文件和设备文件:

  普通文件 是指驻留在磁盘或其它外部介质上的一个有序数据集。可以是源文件、目标文件、可执行程序(可以称作程序文件);也可以是一组待输入处理的原始数据,或者是一组输出的结果(可称作数据文件)。

printf,putchar等。键盘通常被指定标准的输入文件,相关函数有scanf,getchar等。

 

从文件编码的方式来看,分为ASCII码文件和二进制码文件:

ASCII文件也称为文本文件,这种文件在磁盘中存放时每个字符对应一个字节,用于存放对应的ASCII码。

例如,数5678的存储形式为:

BYTE:  00110101 00110110 00110111 00111000

↓↓↓↓

ASCII:  '5''6'    '7''8'

共占用4个字节。ASCII码文件可在屏幕上按字符显示,例如源程序文件就是ASCII文件,用DOS命令TYPE可查看文件的内容。

  二进制文件是按二进制的编码方式来存放文件的。 

例如,数5678的存储形式为: 

00010110 00101110

只占二个字节。

 

C系统在处理这些文件时,并不区分类型,都看成是字符流,按字节进行处理。输入输出字符流的开始和结束只由程序控制而不受物理符号(如回车符)的控制。 因此也把这种文件称作"流式文件"。 // C语言中还有 IO型文件

 


 

本节学习流式文件的打开、关闭、读、写、 定位等各种操作。

在讲这些函数之间,先了解一个概念 FILE

 

文件指针

在C语言中用一个指针变量指向一个文件,通过文件指针可对文件进行各种操作。 

 

FILE* 指针变量标识符; 

其中

FILE,是由系统定义的一个结构, 该结构中含有文件名、文件状态和文件当前位置等信息。 各种文件操作函数已经封装了对它的操作,用户编程操作文件时不必关心FILE结构的细节。

例如:

FILE *fp; 表示fp是指向FILE结构的指针变量,通过fp 即可找存放某个文件信息的结构变量,然后按结构变量提供的信息找到该文件, 实施对文件的操作。FILE结构关联一个文件,打开文件时建立此关联,关闭文件时断开关联。习惯上把fp称为指向一个文件的指针。

流式文件 打开和关闭函数

文件的打开与关闭文件在进行读写操作之前要先打开,使用完毕要关闭。 所谓打开文件,实际上是建立文件的各种有关信息, 并使文件指针指向该文件,以便进行其它操作。关闭文件则断开指针与文件之间的联系,也就禁止再对该文件进行操作。

文件打开函数 fopen

文件指针名=fopen(文件名,使用文件方式) 

其中

"文件指针名" 是被说明为FILE 类型的指针变量。

"文件名" 是被打开文件的文件名, 是字符串常量或字符数组。

"使用文件方式"是指文件的类型和操作要求。

 

例如:

在当前目录下打开文件file a, 只允许进行"读"操作。

FILE *fp;

fp=("fileA","r");

 

例如:

打开C驱动器磁盘的根目录下的文件hzk16, 这是一个二进制文件,只允许按二进制方式进行读操作。

FILE *fphzk

fphzk=("c:\\hzk16","rb")

 

使用文件的方式共有12种

方式

意 义

"rt"

只读打开 文本文件

"wt"

只写打开或建立 文本文件

"at"

追加打开 文本文件

"rb"

只读打开 二进制文件

"wb"

只写打开或建立 二进制文件

"ab"

追加打开 二进制文件

"rt+"

读写打开 文本文件

"wt+"

读写打开或建立 文本文件

"at+"

读写打开文本文件,可追加

"rb+"

读写打开二进制文件

"wb+"

读写打开或建立二进制文件

"ab+"

读写打开二进制文件,可追加

 

说明:

1. 文件使用方式由r,w,a,t,b,+六个字符拼成,各字符的含义是:

r(read)   读

w(write)  写

a(append) 追加

+        读和写

t(text)    文本文件,可省略不写

b(banary) 二进制文件

 

2. 用"r"打开的文件只能读,且文件必须已经存在。

 

3. 用"w"打开的文件只能写。

 

4. 用"a"打开的文件只能写,内容追加。文件必须已经存在,否则出错。

 

5. 打开文件出错时,fopen将返回 NULL。

 

6. 对于文本文件,读入内存时转换为二进制形式,写入硬盘时转换为文本形式,转换需要一点点时间。对二进制文件的读写不存在这种转换。

 

7. 文件使用完毕,应关闭之,以避免数据丢失等错误。

 

8. 标准输入文件(键盘),标准输出文件(显示器 ),标准出错输出(出错信息)由系统打开,可直接使用。

文件关闭函数fclose

fclose(文件指针); 

正常关闭时返回0,否则返回非零。

 

流式文件的读写

C提供多种文件读写的函数:

·字符读写函数 :fgetc和fputc

·字符串读写函数:fgets和fputs

·数据块读写函数:freed和fwrite

·格式化读写函数:fscanf和fprinf

文件操作函数说明在头文件stdio.h。

字符读写函数 fgetc, fputc

一、读字符函数fgetc

=fgetc(文件指针); 

例如:

ch=fgetc(fp); 

 

说明:

可连续多次使用fgetc函数,读取多个字符。在文件内部有一个位置指针,指向文件的当前读写字节。在文件打开时,该指针总是指向文件的第一个字节。使用fgetc函数后,该位置指针将向后移动一个字节。 

应区别 文件指针和文件内部的位置指针不是一回事。

文件指针 是指向整个文件的,须在程序中定义说明,只要不重新赋值,文件指针的值是不变的。

文件内部的位置指针 用以指示文件内部的当前读写位置,每读写一次,该指针均向后移动,它不需在程序中定义说明,而是由系统自动设置的。

 

二、写字符函数fputc

fputc(字符量,文件指针); 

其中,待写入的字符量可以是字符常量或变量

例如:

fputc('a',fp);

 

说明:

1. 被写入的文件可以用写、读写、追加方式打开,用写或读写方式打开一个已存在的文件时将清除原有的文件内容,写入字符从文件首开始。被写入的文件若不存在,则创建该文件。

 

2. 每写入一个字符,文件内部位置指针向后移动一个字节。

 

3. fputc函数有一个返回值,如写入成功则返回写入的字符, 否则返回一个EOF。

 

字符读写示例:

从键盘输入一行字符,写入一个文件, 再把该文件内容读出显示在屏幕上。 

#include<stdio.h>

 main()
{
FILE *fp;
char ch;

if((fp=fopen("string","wt+"))==NULL)
{
printf("Cannot open file strike any key exit!");
 //getch();
exit(1);
}

printf("input a string:\n");
 ch=getchar();
while (ch!='\n')
{
fputc(ch,fp);
 ch=getchar();
}

rewind(fp);

 ch=fgetc(fp);
while(ch!=EOF)
{
putchar(ch);
 ch=fgetc(fp);
}
printf("\n");

fclose(fp);
}

字符读写示例:
把命令行参数中的前一个文件名标识的文件, 复制到后一个文件名标识的文件中, 如命令行中只有一个文件名则把该文件写到标准输出文件(显示器)中。

#include<stdio.h> main(int argc,char *argv[]){FILE *fp1,*fp2;char ch;if(argc==1){printf("无文件名,请至少指定输入文件!"); //getch();exit(0);}if((fp1=fopen(argv[1],"rt"))==NULL){printf("不能打开输入文件 %s\n",argv[1]); //getch();exit(1);}if(argc==2)     fp2=stdout;else if((fp2=fopen(argv[2],"wt+"))==NULL){printf("不能打开输出文件 %s\n",argv[1]); //getch();exit(1);}while((ch=fgetc(fp1))!=EOF)  fputc(ch,fp2);fclose(fp1);fclose(fp2);}

 

字符串读写函数 fgets, fputs

一、读字符串函数fgets

fgets(字符数组名,n,文件指针); 

其中

n是一个正整数, 表示从文件中读出的字符串不超过 n-1个字符。在读入的最后一个字符后加上串结束标志 '\0' 。

说明:

1. 在读出n-1个字符之前,如遇到了换行符或EOF,则结束。 // 串结束符

2. fgets函数也有返回值,其返回值是字符数组的首地址。

二、写字符串函数fputs

fputs(字符串,文件指针) 

其中 字符串可以是字符串常量,字符数组名,指针变量。

例如:

向一文件写入一串,然后读取前10字符。

#include <stdio.h> main(){FILE *fp;char str[128]="0123456789";char ch;if((fp=fopen("str","wt+"))==NULL){printf("打开文件失败!");// getch();exit(1);}printf("请输入一串:");scanf("%12s",str); // receive 12 chars, and storage 0 behind!// scanf("%12s", tr); // receive rest chars in istream!puts(str);fputs(str,fp);rewind(fp);fgets(str, 11, fp); // read at most 10 chars, and storage 0 behind!puts(str);fclose(fp);}/* 请输入一串:01234567891011 012345678910 0123456789 Press any key to continue */


数据块读写函数 fread, fwrite

  可用来读写一组数据,如数组,结构等块数据。

fread(buffer,size,count,fp); 

fwrite(buffer,size,count,fp); 

其中

buffer是一个指针,表示存放数据块的首地址。

size 表示数据块的字节数。

count 表示要读写的数据块块数。

fp 表示文件指针。

例如:

fread(fa,4,5,fp); 其意义是从fp所指的文件中,每次读4个字节(一个实数)送入实数组fa中,连续读5次,即读5个实数到fa中。

例如:

从键盘输入两个学生数据,写入一个文件中, 再读出这两个学生的数据显示在屏幕上。

// 注意: scanf("%s%d", str, &iv); 输入串时不能有空格! 如果允许空格,使用gets。#include<stdio.h>struct stu{char name[10];int num;int age;char addr[15];}boya[2],boyb[2],*pp,*qq; main(){FILE *fp;char ch;int i; pp=boya; qq=boyb;if((fp=fopen("stu_list","wb+"))==NULL){printf("Cannot open file strike any key exit!"); // getch();exit(1);}printf("\ninput data\n");for(i=0;i<2;i++,pp++)scanf("%s%d%d%s",pp->name,&pp->num,&pp->age,pp->addr); pp=boya;fwrite(pp,sizeof(struct stu),2,fp);rewind(fp);fread(qq,sizeof(struct stu),2,fp);printf("\n\nname\tnumber age addr\n");
for(i=0;i<2;i++,qq++)printf("%s\t%5d%7d%s\n",qq->name,qq->num,qq->age,qq->addr);fclose(fp);}


 

格式化读写函数fscanf,fprintf

与前面使用的scanf和printf 函数的功能相似,都是格式化读写函数。区别在于 fscanf 函数和fprintf函数的读写对象不是键盘和显示器,而是磁盘文件。

格式: 

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

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

例如:

fscanf(fp,"%d%s",&i,s);

fprintf(fp,"%d%c",j,ch);

用fscanf和fprintf函数也可以实现前面的操作。

格式化读写的问题: 串中不能有空格!

例如:

 

#include<stdio.h>struct stu{char name[10];int num;int age;char addr[15];}boya[2], *pp; main(){FILE *fp;char ch;int i;if((fp=fopen("stu_list","wa+"))==NULL){printf("Cannot open file strike any key exit!");exit(1);} pp=boya;for(i=0;i<2;i++,pp++){printf(" student %d/2 \n", i);scanf("%s%d%d%s",pp->name,&pp->num,&pp->age,pp->addr);fprintf(fp,"%s %d %d %s\n",pp->name,pp->num,pp->age,pp->addr);printf("%s %d %d %s\n",pp->name,pp->num,pp->age,pp->addr);}rewind(fp); pp = boya;for(i=0;i<2;i++,pp++){printf(" student %d/2 \n", i);fscanf(fp, "%s %d %d %s",pp->name,&pp->num,&pp->age,pp->addr);printf("%s %d %d %s\n",pp->name,pp->num,pp->age,pp->addr);}fclose(fp);}


 

文件的随机读写

读写文件中某一指定的部分。 这就需要移动位置指针,也称文件的定位。文件定位函数主要有两个 rewind 函数和fseek函数。// 还有ftell 

rewind函数

把文件内部的位置指针移到文件首。 

rewind(文件指针); 

fseek函数

移动文件内部位置指针

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

其中

"文件指针"指向被移动的文件。 

"位移量"表示移动的字节数,要求位移量是long型数据,以便在文件长度大于64KB (// ? 超过了怎么办 )时不会出错。当用常量表示位移量时,要求加后缀"L"。

"起始点"表示从何处开始计算位移量,起始点有三种:文件首,当前位置和文件尾。

 

起始点    符号    值

────────────────────

文件首      SEEK—SET  0

当前位置    SEEK—CUR  1

文件末尾   SEEK—END  2

 

例如:

把位置指针移到离文件首100个字节处。

fseek(fp,100L,0);

 

说明

fseek函数一般用于二进制文件。在文本文件中由于要进行转换,故往往计算的位置会出现错误。

文件的随机读写在移动位置指针之后,可用前面介绍的任一种读写函数进行读写。一般是用fread和fwrite读写一个数据据块。

例如:

前面的例子中输出文件中存储了3个学生成绩,读出第2个学生的信息,并修改它。

...

文件检测函数

一、文件结束检测函数 feof

feof(文件指针);

判断文件是否处于文件结束位置,如文件结束,则返回值为1,否则为0。

 

二、读写文件出错检测函数 ferror

ferror(文件指针);

检查文件在用各种输入输出函数进行读写时是否出错。 如ferror返回值为0表示未出错,否则表示有错。

 

三、文件出错标志和文件结束标志置0函数 clearerr

clearerr(文件指针);

清除出错标志和文件结束标志。

 

 


本章小结

1. C系统把文件当作一个"流",按字节进行处理。

2. C文件按编码方式分为二进制文件和ASCII文件。

3. C语言中,用文件指针标识文件,当一个文件被 打开时, 可取得该文件指针。

4. 文件在读写之前必须打开,读写结束必须关闭。

5. 文件可按只读、只写、读写、追加四种操作方式打开,同时还必须指定文件的类型是二进制文件还是文本文件。

6. 文件可按字节,字符串,数据块为单位读写,文件也可按指定的格式进行读写。

7. 文件内部的位置指针可指示当前的读写位置,移动该指针可以对文件实现随机读写。