Download presentation
Presentation is loading. Please wait.
1
C 语言程序设计 文件 周闻钧 朱宏明
2
本讲内容 文件的概念 文件指针 文件的读写 文件的定位
3
文件 所谓“文件”一般指:存储在外部介质上数据的集合,一批数据是以文件的形式存放在外部介质(如磁盘)上的
操作系统是以文件为单位对数据进行管理的,也就是说,如果想找存在外部介质上的数据,必须先按文件名找到所指定的文件,然后再从该文件中读取数据。向外部介质上存储数据也必须先建立一个文件(以文件名标识),才能向它输出数据
4
文件 C语言把文件看作是一个字符(字节)的序列,即由一个个字符(字节)的数据顺序组成。根据数据的组织形式,可分为ASCII文件和二进制文件
ASCII文件又称文本(text)文件,它的每一个字节放一个ASCII代码,代表一个字符 二进制文件是把内存中的数据按其在内存中的存储形式原样输出到磁盘上存放。如果有一个整数10000,在内存中占2个字节,如果按ASCII形式输出,则占5个字节,而按二进制形式输出,在磁盘上只占2个字节。用ASCII码形式输出与字符一一对应
5
文件 一个字节代表一个字符,因而便于对字符进行逐个处理,也便于输出字符。但一般占存储空间较多,而且要花费转换时间(二进制形式与ASCII码间的转换) 用二进制形式输出数值,可以节省外存空间和转换时间,但一个字节并不对应一个字符,不能直接输出字符形式。一般中间结果数据需要暂时保存在外存上以后又需要输入到内存的,常用二进制文件保存
6
文件 一个C文件是一个字节流或二进制流 它把数据看作是一连串的字符(字节),而不考虑记录的界限
换句话说,c语言中文件并不是由记录(record)组成的(这是和PASCAL或其它高级语言不同的)
7
文件 在C语言中对文件的存取是以字符(字节)为单位的。输入输出的数据流的开始和结束仅受程序控制而不受物理符号(如回车换行符)控制。我们把这种文件称为流式文件。C语言允许对文件存取一个字符,就增加了处理的灵活性。 在过去使用的C版本(如unix系统下使用的C)有两种对文件的处理方法: 一种叫“缓冲文件系统”, 一种叫“非缓冲文件系统”
8
文件 所谓缓冲文件系统是指:系统自动地在内存区为每一个正在使用的文件名开辟一个缓冲区。从内存向磁盘输出数据必须先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘去。如果从磁盘向内存读入数据,则一次从磁盘文件将一批数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(给程序变量)。缓冲区的大小由各个具体的C版本确定,一般为512字节 所谓“非缓冲文件系统”是指系统不自动开辟确定大小的缓冲区,而由程序为每个文件设定缓冲区
9
文件 在UNIX系统下,用缓冲文件系统来处理文本文件,用非缓冲文件系统处理二进制文件
用缓冲文件系统进行的输入输出又称为高级(或高层)磁盘输入输出(高层I/O),用非缓冲进行的输入输出又称为低级(低层)输入输出系统 1983年ANSI C标准决定不采用非缓冲文件系统,而只采用缓冲文件系统。即既用缓冲文件系统处理文本文件,也用它来处理二进制文件。也就是将缓冲文件系统扩充为可以处理二进制文件 在C语言中,没有输入输出语句,对文件的读写都是用库函数来实现的
10
文件类型指针 缓冲文件系统中,关键的概念是--文件指针。每个被使用的文件都在内存中开辟一个区,用来存放文件的有关信息(如文件的名字、文件状态及文件当前位置等)。这些信息是保存在一个结构体类型的变量中的。该结构体类型是由系统定义的,取名为FILE typedef struct { int _fd; /*文件号*/ int _cleft; /*缓冲区中剩下的字符*/ int _mode; /*文件操作模式*/ char _nextc;/*下一个字符位置*/ char _buff;/*文件缓冲区位置*/ }FILE;
11
文件类型指针 在vc中的定义 struct _iobuf { char *_ptr; int _cnt; char *_base;
#ifndef _FILE_DEFINED struct _iobuf { char *_ptr; int _cnt; char *_base; int _flag; int _file; int _charbuf; int _bufsiz; char *_tmpfname; }; typedef struct _iobuf FILE; #define _FILE_DEFINED #endif
12
文件类型指针 有了FILE类型之后,可以用它来定义若干个FILE类型的变量,以便存放若干个文件的信息
可以定义以下FILE类型的数组。FILE _efile[5] 可以定义文件型指针变量。FILE *fp; fp是一个指向FILE类型结构体的指针变量。可以使fp指向某一个文件的结构体变量,从而通过该结构体变量中的文件信息能够访问该文件。也就是说,通过文件指针变量能够找到与它相关的文件 如果有n个文件,一般应设n个指针变量(指向FILE类型结构体的指针变量),使它们分别指向n个文件(确切他说,指向该文件的信息结构体),以实现对文件的访问
13
文件的打开 文件的打开(fopen函数) ANSI C规定了标准输入输出函数库,用fopen函数来实现打开文件。fopen函数的调用方式通常为: FILE *fp; fp = fopen(文件名,使用文件方式); 例如 fp = fopen(”c:\aaa.txt”,”r”) 要打开c盘中的aaa.txt文件,使用文件方式为“读入”,fopen函数带回指向aaa文件的指针并赋给fp,这样fp就和aaa相联系了,或者说,fp指向aaa文件
14
文件的打开 在打开一个文件时,通知给编译系统以下三个信息 需要打开的文件名,也就是准备访问的文件名 使用文件的方式(读还是写等)
让哪一个指针变量指向被打开的文件
15
文件的打开 文件使用方式 含义 R 只读,输入用 W 只写,输出用 A 为文本文件尾增加数据 Rb 输入二进制文件 Wb 输出二进制文件
Ab 增加二进制文件 R+ 为读/写打开一个文件 W+ 为读/写建立一个新文件 A+ Rb+ 为读/写打开二进制文件 Wb+ 为读/写建立一个新二进制文件 Ab+
16
文件的打开 用r方式打开的文件只能用于向计算机输入而不能用作向该文件输出数据,而且该文件应该已经存在,不能打开一个并不存在的用于r方式的文件,否则出错 用w方式打开的文件只能用于向该文件写数据,而不能用来向计算机输入。如果原来不存在该文件,则在打开时新建立一个以指定名字命名的文件。如果原来已存在一个以该文件名命名的文件,则在打开时将该文件删去,然后重新建立一个新文件 如果希望向文件末尾添加新的数据(不希望删除原有数据),则应该用a方式打开。但此时该文件必须已存在,否则将得到出错信息。打开时,位置指针移到文件末尾
17
文件的打开 用r+、w+、a+方式打开的文件可以用来输入和输出数据。用r+方式时该文件应该已经存在,以便能向计算机输入数据。用w+,方式则新建立一个文件,先向此文件写数据,然后可以读此文件中的数据。用a+方式打开的文件,原来的文件不被删去 如果不能实现打开的任务,fopen函数将会带回一个出错信息。出错的原因可能是:用r方式打开一个并不存在的文件,磁盘出故障,磁盘已满无法建立新文件等。此时fopen函数将带回一个空指针值NULL(NULL在stdio.h文件中已被定义为0)
18
文件的打开 用以上方式可以打开文本文件或二进制文件,这是ANSI C的规定,用同一种缓冲文件系统来处理文本文件和二进制文件。但目前使用的有些C编译系统可能不完全提供所有这些功能(例如有的只能用r,w,a方式),有的c版本不用r+,w+,a+而用rw、wr、ar等 在用文本文件向计算机输入时,将回车换行符转换为一个换行符,在输出时把换行符转换成为回车和换行两个字符,在用二进制文件时,不进行这种转换,在内存中的数据形式与输出到外部文件中的数据形式完全一致 程序开始运行时,系统自动打开三个标准文件:标准输入、标准输出、标准出错输出。通常这三个文件都与终端相联系。因此以前我们所用到的从终端输入或输出,都不需要打开终端文件系统自动定义了三个文件指针stdin、stdout,stderr,分别指向终端输入输出出错输出(也从终端输出)
19
文件的关闭 在使用完一个文件后应该关闭它,以防止它再被误用。关闭,就是使文件指针变量不指向该文件,也就是文件指针变量与文件脱钩,此后不能再通过该指针对其相连的文件进行读写操作,除非再次打开,使该指针变量重新指向该文件 用fclose函数关闭文件 一般形式为 flose(文件指针); 例如 flose(fp)
20
文件的关闭 用fopen函数打开文件时所带回的指针赋给了fp,应该养成在程序终止之前关闭所有使用的文件的习惯,如果不关闭文件将会丢失数据
在向文件写数据时,是先将数据输到缓冲区,待缓冲区充满后才正式输出给文件。如果当数据未充满缓冲区而程序结束运行,就会将缓冲区中的数据丢失。用fclose函数关闭文件,可以避免这个问题,它先把缓冲区中的数据输出到磁盘文件然后才释放文件指针变量 fclose函数也带回一个值:当顺利地执行了关闭操作,则返回值为0;如果返回值为非零值,则表示关闭时有错误。可以用ferror函数来测试
21
文件的读写 fputc函数把一个字符写到磁盘文件上去。其一般形式为 fputc(ch,fp)
其中ch是要输出的字符,它可以是一个字符常量,也可以是一个字符变量。fp是文件指针变量,它从fopen函数得到返回值。上面fputc函数的作用是将字符输出到fp所指向的文件上去。 fputc函数也带回一个值:如果输出成功则返回值就是输出的字符;如果输出失败,则返回一个EOF EOF是在stdio.h文件中定义的符号常量,值为-1
22
文件的读写 fgetc函数从指定文件读入一个字符,该文件必须是以读或读写方式打开的,fgetc函数的调用形式为ch = fgetc(fp);
fp为文件型指针变量,ch为字符变量。fgetc函数带回一个字符,赋给ch。如果在执行fgetc读字符时遇到文件结束符,函数返回一个文件结束标志EOF,EOF在stdio.h中定义为-1
23
文件的读写 EOF不是可输出字符,因此不能在屏幕上显示。由于字符的ASCII码不可能出现-1,因此EOF定义为-1是合适的。当读入的字符值等于-1,即EOF时,表示读入的已不是正常的字符而是文件结束符。但以上只适用于读文本文件的情况。现在ANSI C已允许用缓冲文件系统处理二进制文件,而读入某一个字节中的二进制数据的值有可能是-1,而这又恰好是EOF的值。这就出现了需要读人有用数据而却被处理为”文件结束”的情况。 为了解决这个问题,ANSI C提供一个feof函数来判断文件是否真的结束。Feof(fp)用来测试fp所指向的文件当前状态是否文件结束。如果是文件结束,函数feof(fp)的值为1(真),否则为0(假)
24
文件的读写 用getc和putc函数可以用来读写文件中的一个字符
但是常常要求一次读入一组数据(例如,一个实数或一个结构体变量的值),ANSI C标准提出设置两个函数(fread和fwrite),用来读写一个数据块。它们的一般调用形式为: fread(buffer,size,count,fp); fwrite(buffer,size,count,fp); buffer:是一个指针。对fread来说,它是读入数据的存放地址。对fwrite来说,是要输出数据的地址(以上指的是起始地址) size:要读写的字节数 count:要进行读写多少个size字节的数据项 fp:文件型指针
25
文件的读写 fprintf函数、fscanf函数与printf函数、scanf函数作用相仿,都是格式化读写函数。只有一点不同:fprintf和fscanf函数的读写对象不是终端而是磁盘文件。一般调用方式为: fprintf(文件指针,格式字符串,输出表列); fscanf(文件指针,格式字符串,输入表列); 用fprintf和fscanf函数对磁盘文件读写,使用方便,容易理解,但由于在输入时需要将ASCII码转换为二进制形式,在输出时又要将二进制形式转换成字符,花费时间比较多。因此,在内存与磁盘频繁交换数据的情况下,最好不用fprintf和fsrintf函数,而用fread和fwrite函数
26
文件的读写 putw和getw函数 大多数C编译系统都提供另外两个函数:putw和getw,用来对磁盘文件读写一个字(整数)。
例如putw(10,fp);它的作用是将整数10输出到fp指向的文件。 而i=getw(fp);它的作用是从磁盘文件读一个整数到内存,赋给整型变量I putw和getw并不是ANSIC标准定义的函数。但许多C编译都提供这两个函数(例如Microsoft4.0有putw和getw函数),但有的C编译可能不以putw和getw命名此两函数,而用其它函数名
27
文件的读写 fgets的作用是从指定文件读入一个字符串。
如fgets(str,n,fp);从fp指向的文件输入n一1个字符,并把它们放到字符数组str中。如果在读入n-1个字符结束之前遇到换行符或EOF,读入即结束。字符串读入后在最后加一个’\0’字符,fgets函数返回值为str的首地址。 fputs函数的作用是向指定的文件输出一个字符串。 如fputs(“China”,fp);把字符串“China”,输出到fp指向的文件。fputs函数中第一个参数可以是字符串常量、字符数组名或字符型指针。输出成功,函数值为0;失败时,为非零值。 这两个函数类似以前介绍过的gets和puts函数,只是fgets和fputs函数以指定的文件作为读写对象
28
文件的定位 文件中有一个位置指针,指向当前读写的位置。如果顺序读写一个文件,每次读写一个字符,则读写完一个字符后,该位置指针自动移动指向下一个字符位置。如果想改变这样的规律,强制使位置指针指向其它指定的位置,可以用有关函数
29
文件的定位 rewind函数 fseek函数 ftell函数 使位置指针重新返回文件的开头。此函数没有返回值 实现改变文件的位置指针
得到流式文件中的当前位置
30
文件的定位 对流式文件可以进行顺序读写,也可以进行随机读写。关键在于控制文件的位置指针,如果位置指针是按字节位置顺序移动的,就是顺序读写。如果可以将位置指针按需要移动到任意位置,就可以实现随机读写。所谓随机读写,是指读写完上一个字符(字节)后,并不一定要读写其后续的字符(字节),而可以读写文件中任意所需的字符(字节) fseek函数的调用形式为 fseek(文件类型指针,位移量,起始点)
31
文件的定位 起始点用0.1或2代替,0代表“文件开始”,1为“当前位置”,2为“文件末尾”。ANSIC标准指定以下的名字:
起始点 名字 用数字代表 文件开始 SEEK_SET 0 文件当前位置 SEEK_CUR 1 文件末尾 SEEK_END 2 “位移量”指以“起始点”为基点,向前移动的字节数。ANSIC和大多数C版本要求位移是long型数据。这样当文件的长度大于64K时不致出问题。ANSIC标准规定在数字的末尾加一个字母L,就表示是long型
32
文件的定位 ftell函数的作用是得到流式文件中的当前位置,用相对于文件开头的位移量来表示
如果ftell函数返回值为-1L,表示出错
33
文件出错的检测 ferror函数 在调用各种输入输出函数(如putc.getc.fread.fwrite等)时,如果出现错误,除了函数返回值有所反映外,还可以用ferror函数检查。它的一般调用形式ferror(fp); 如果ferror返回值为0,表示未出错。如果返回一个非零值,表示出错 对同一个文件每一次调用输入输出函数,均产生一个新的ferror函数值,因此,应当在调用一个输入输出函数后立即检查ferror函数的值,否则信息会丢失 在执行fopen函数时,ferror函数的初始值自动置为0
34
文件的出错检测 clearerr函数 它的作用是使文件错误标志和文件结束标志置为0
假设在调用一个输入输出函数时出现错误,ferror函数值为一个非零值。在调用clearerr(fp)后, ferror(fp)的值变成0。 只要出现错误标志,就一直保留,直到对同一文件调用clearerr函数或rewind函数,或任何其它一个输入输出函数
Similar presentations