
第12章文件 引言 在程序设计中,往往要对大量数据进行处理。许多程序在实现过程中,依赖于把数据 保存到变量中,而变量是通过内存单元存储数据的,数据的处理完全由程序控制。当一个 程序运行完成或者终止运行,所有变量的值不再保存。另外,一般的程序都会有数据输入 与输出,如果输入输出数据量不大,通过键盘和显示器就可方便解决,而当数据较多时就 极为繁琐。例如,学生成绩管理系统要用到学生的学号、姓名以及课程成绩等数据,对于 一个几千人的中等规模的院校,可能要对几万到几十万个数据进行处理,数据量很大。 文件是解决上述问题的有效办法,它通过把数据存储在磁盘文件中,得以长久保存。 每次运行程序时从磁盘文件中读取数据,程序的输出数据也存入磁盘中,这就为程序运行 提供了很大方便。为此,C语言提供了一系列对磁盘文件进行的操作。 本章将重点介绍文件的概念、文件的分类以及文件操作的相关函数,包括fopen(、 fclose()、fgetc()、fpute(、)fprintf0(、fscnaf0、fgets(、fputs()、exit()、ffush()、fread( fwrite(),rewind()、fseek()、feof(). 12.1文件概述 12.1.1文件的概念 文件是指一组相关数据的有序集合,文件通常是驻留在外部存储介质(如磁盘等)上 的,在使用时才调入内存。比如stdio.h就是一个包含一些有用信息的文件的名称。 与计算机内存存储数据不同,文件通常对应于程序的地址空间之外的存储器,比如U 盘或硬盘。存取数据的细节都是由操作系统来实现的,程序员只需要考虑的是如何在C程 序中处理文件。 12.1.2文件的分类 可以从不同的角度对文件进行分类。 从用户的角度,文件可分为普通文件和设备文件两种。普通文件是指驻留在磁盘或其 他外部介质上的一个数据集,可以是源文件、目标文件、可执行程序,也可以是一组待输 入处理的原始数据,或者是一组输出结果:设备文件是指与主机相关联的各种外部设备, 如显示器、打印机、键盘等。 从文件编码的角度,文件可分为文本文件和二进制文件两种。两者的差别在于存储数 值型数据的方式不同。文本文件将数值型数据的每一位数字作为一个字符以其ASCI码的 形式存储,例如源程序文件、记事本文件等都是文本文件,用DOS命令TYPE可显示文
第 12 章 文件 引言: 在程序设计中,往往要对大量数据进行处理。许多程序在实现过程中,依赖于把数据 保存到变量中,而变量是通过内存单元存储数据的,数据的处理完全由程序控制。当一个 程序运行完成或者终止运行,所有变量的值不再保存。另外,一般的程序都会有数据输入 与输出,如果输入输出数据量不大,通过键盘和显示器就可方便解决,而当数据较多时就 极为繁琐。例如,学生成绩管理系统要用到学生的学号、姓名以及课程成绩等数据,对于 一个几千人的中等规模的院校,可能要对几万到几十万个数据进行处理,数据量很大。 文件是解决上述问题的有效办法,它通过把数据存储在磁盘文件中,得以长久保存。 每次运行程序时从磁盘文件中读取数据,程序的输出数据也存入磁盘中,这就为程序运行 提供了很大方便。为此,C 语言提供了一系列对磁盘文件进行的操作。 本章将重点介绍文件的概念、文件的分类以及文件操作的相关函数,包括 fopen()、 fclose()、fgetc()、fputc()、fprintf()、 fscnaf()、fgets()、 fputs()、exit()、fflush()、fread()、 fwrite()、rewind()、fseek()、feof()。 12.1 文件概述 12.1.1 文件的概念 文件是指一组相关数据的有序集合,文件通常是驻留在外部存储介质(如磁盘等)上 的,在使用时才调入内存。比如 stdio.h 就是一个包含一些有用信息的文件的名称。 与计算机内存存储数据不同,文件通常对应于程序的地址空间之外的存储器,比如 U 盘或硬盘。存取数据的细节都是由操作系统来实现的,程序员只需要考虑的是如何在 C 程 序中处理文件。 12.1.2 文件的分类 可以从不同的角度对文件进行分类。 从用户的角度,文件可分为普通文件和设备文件两种。普通文件是指驻留在磁盘或其 他外部介质上的一个数据集,可以是源文件、目标文件、可执行程序,也可以是一组待输 入处理的原始数据,或者是一组输出结果;设备文件是指与主机相关联的各种外部设备, 如显示器、打印机、键盘等。 从文件编码的角度,文件可分为文本文件和二进制文件两种。两者的差别在于存储数 值型数据的方式不同。文本文件将数值型数据的每一位数字作为一个字符以其 ASCII 码的 形式存储,例如源程序文件、记事本文件等都是文本文件,用 DOS 命令 TYPE 可显示文

件的内容:二进制文件是将数值型数据以二进制形式存放的,例如可执行C程序的内容是 存储在二进制文件中的。文本文件中字节表示字符,由于是按字符显示,因此能读懂文件 内容:二进制文件字节不一定表示字符,字节组也可以表示整数和浮点数,虽然也可在屏 幕上显示,但其内容无法读懂。 前面我们已经介绍计算机的存储在物理上是二进制的,所以文本文件与二进制文件的 区别并不是物理上的,而是逻辑上的,这两者只是在编码层次上有差异。例如整型数据5678 以二进制形式存储需要两个字节的存储空间,见表121:而以文本文件存储则需要四个字 节的存储空间,见表122 表12-1二进制文件中数据5678占2个字节 0001011000101110 表12-2文本文件中数据5678占4个字节 字符 5 *6 479 8* 十进制的ASCI码 53 54 55 56 ASCIⅡ码转换为二进制 00110101 0011011000110111 00111000 C系统在处理这些文件时,并不区分类型,都看成是字符流,按字节进行处理。输入 输出字符流的开始和结束只由程序控制而不受物理符号(如回车符)的控制。因此也把这种 文件称作“流式文件”。 12.1.3标准文件V0 编程从文件读取信息或者将结果写入文件是一种经常性的需求。为此,C提供了功能 强大的文件通信方法。使用这种方法可以在程序中打开文件,然后使用专门的0函数读 取或者写入文件 C语言通信有交互式VO和文件VO两种方式。交互式VO意味着与人或物理设备通信, 人或设备都与运行着的程序并行工作,送给程序的输入可能依赖于程序在此前的输出(例 如提示)。到目前为止,我们所讨论的例子都是从标准输入读取数据并向标准输出输出数据。 标准高级I/O(standard high-level I/O)使用一个标准的C库函数包和stdio.h头文件中的 定义。标准VO包中包含很多专用的函数,可以方便地处理不同的VO问题。例如,printf) 将各种类型的数据转换成为活合终瑞的字符串输出。 同时,文件VO允许C将数据保存到文件中或者从文件中读取数据。标准O对输入 和输出进行了缓冲。也就是在读写文件时,会把一大块数据复制到缓冲区(一块中介存储 区)中,再传给C语言程序或外存上。这种缓冲大大提高了数据传输率。随后程序就可以分 析缓冲区中的个别字节,缓冲过程是在后台处理的,所以你会产生逐字节读取的错觉。 ANSI C采用缓冲文件系统,即既用缓冲文件系统处理文本文件,也用它来处理二进 制文件。本章主要介绍ANSIC规定的缓冲文件系统以及对它的读写。 2
2 件的内容;二进制文件是将数值型数据以二进制形式存放的,例如可执行 C 程序的内容是 存储在二进制文件中的。文本文件中字节表示字符,由于是按字符显示,因此能读懂文件 内容;二进制文件字节不一定表示字符,字节组也可以表示整数和浮点数,虽然也可在屏 幕上显示,但其内容无法读懂。 前面我们已经介绍计算机的存储在物理上是二进制的,所以文本文件与二进制文件的 区别并不是物理上的,而是逻辑上的。这两者只是在编码层次上有差异。例如整型数据 5678 以二进制形式存储需要两个字节的存储空间,见表 12-1;而以文本文件存储则需要四个字 节的存储空间,见表 12-2: 表 12-1 二进制文件中数据 5678 占 2 个字节 00010110 00101110 表 12-2 文本文件中数据 5678 占 4 个字节 字符 ‘5’ ‘6’ ‘7’ ‘8’ 十进制的 ASCII 码 53 54 55 56 ASCII 码转换为二进制 00110101 00110110 00110111 00111000 C 系统在处理这些文件时,并不区分类型,都看成是字符流,按字节进行处理。输入 输出字符流的开始和结束只由程序控制而不受物理符号(如回车符)的控制。 因此也把这种 文件称作“流式文件”。 12.1.3 标准文件 I/O 编程从文件读取信息或者将结果写入文件是一种经常性的需求。为此,C 提供了功能 强大的文件通信方法。使用这种方法可以在程序中打开文件,然后使用专门的 I/O 函数读 取或者写入文件。 C 语言通信有交互式 I/O 和文件 I/O 两种方式。交互式 I/O 意味着与人或物理设备通信, 人或设备都与运行着的程序并行工作,送给程序的输入可能依赖于程序在此前的输出(例 如提示)。到目前为止,我们所讨论的例子都是从标准输入读取数据并向标准输出输出数据。 标准高级 I/O (standard high-level I/O) 使用一个标准的 C 库函数包和 stdio.h 头文件中的 定义。标准 I/O 包中包含很多专用的函数,可以方便地处理不同的 I/O 问题。例如,printf() 将各种类型的数据转换成为适合终端的字符串输出。 同时,文件 I/O 允许 C 将数据保存到文件中或者从文件中读取数据。标准 I/O 对输入 和输出进行了缓冲。也就是在读写文件时,会把一大块数据复制到缓冲区 (一块中介存储 区)中,再传给 C 语言程序或外存上。这种缓冲大大提高了数据传输率。随后程序就可以分 析缓冲区中的个别字节,缓冲过程是在后台处理的,所以你会产生逐字节读取的错觉。 ANSI C 采用缓冲文件系统,即既用缓冲文件系统处理文本文件,也用它来处理二进 制文件。本章主要介绍 ANSI C 规定的缓冲文件系统以及对它的读写

12.2文件指针 在C语言中,用一个指针变量指向一个文件,该指针称为文件指针。通过文件指针可 以对文件进行各种操作。定义文件指针的一般形式为: EILE指针变量标识符 说明:FLE是由系统定义的一个结构体,其中含有文件名、文件状态和文件当前位置 等信息,在编写源程序时不必关心LE结构体的细节。 例如:FLE*p, 含义:fp是指向FILE结构体的指针变量,通过fp即可找到存放某个文件信息的结构 体信息,按结构体信息找到该文件,可以实施对文件的操作。习惯上把印称为指向一个文 件的指针,简称文件指针。 12.3文件的打开与关闭 12.3.1文件打开函数(fopen)与程序结束函数(exit) ANSIC规定了标准输入输出函数库.fopen函数用于打开一个文件,这一函数在stdio.h 中声明。其调用的一般形式为:它的 文件指针名=fopen(文件名,文件打开方式): 说明 (1)文件指针名必须是被说明的FLE类型的指针变量。 (2)第一个参数是要打开的文件名,文件名是字符串常量或字符数组,文件名可以包 含路径。更确切地说,是包含该文件名的字符串地址。 (3)第二个参数文件打开方式是用于指定文件打开模式的一个字符串,是指文件的类 型和对文件的操作要求。 fopen()i函数在打开一个文件时,需将以下三个信息通知编译系统:①需要打开的文件 名:②文件打开方式(读还是写等):③让哪一个文件指针变量指向被打开的文件。例如: FILE fp: fp=fopen("c:\\filel.dat","rb"): 含义:以只读方式打开C盘根目录下的二进制文件lel.dat。两个反斜线“W”中的第 个表示转义字符,第二个表示根目录。“b”是文件打开方式,C语言中的文件打开方式 见表12-3。 3
3 12.2 文件指针 在C语言中,用一个指针变量指向一个文件,该指针称为文件指针。通过文件指针可 以对文件进行各种操作。定义文件指针的一般形式为: FILE *指针变量标识符; 说明:FILE 是由系统定义的一个结构体,其中含有文件名、文件状态和文件当前位置 等信息,在编写源程序时不必关心 FILE 结构体的细节。 例如:FILE *fp; 含义:fp 是指向 FILE 结构体的指针变量,通过 fp 即可找到存放某个文件信息的结构 体信息,按结构体信息找到该文件,可以实施对文件的操作。习惯上把 fp 称为指向一个文 件的指针,简称文件指针。 12.3 文件的打开与关闭 12.3.1 文件打开函数(fopen)与程序结束函数(exit) ANSI C规定了标准输入输出函数库。fopen函数用于打开一个文件,这一函数在 stdio.h 中声明。其调用的一般形式为:它的;. 文件指针名=fopen(文件名,文件打开方式); 说明: (1)文件指针名必须是被说明的 FILE 类型的指针变量。 (2)第一个参数是要打开的文件名,文件名是字符串常量或字符数组,文件名可以包 含路径。更确切地说, 是包含该文件名的字符串地址。 (3)第二个参数文件打开方式是用于指定文件打开模式的一个字符串,是指文件的类 型和对文件的操作要求。 fopen()函数在打开一个文件时,需将以下三个信息通知编译系统:①需要打开的文件 名;②文件打开方式(读还是写等);③让哪一个文件指针变量指向被打开的文件。例如: FILE *fp; fp=fopen("c:\\file1.dat","rb"); 含义:以只读方式打开 C 盘根目录下的二进制文件 file1.dat。两个反斜线“\\”中的第 一个表示转义字符,第二个表示根目录。“rb”是文件打开方式,C 语言中的文件打开方式 见表 12-3

表12-3文件打开方式及其含义 文件打开方式 只读打开一个文本文件 只写打开或建 个文本文件,只允许写数据,如果文件存在则重写 超加打开或建立 个文本文件,并在文件末尾写数据 “rb 只 进制文件,只允许读数据 46 只写打开或建立 个二进制文件,只允许写数据,如果文件存在则重写 'ab' 道川开双建立 二进制文件,并在文件术尾写数据 “t+ 读写打开一个文本文件,允许读和写 t+ 读写打开或建立一个文本文件,允许读写,如果文件存在则重写 “at+ 读写打开或建立 一个文本文件,允许读取整个文件,或在文件末追加数据 “rb+ 读写打开一个二进制文件,允许读和写 “wb+ 读写打开或建立一个二进制文件,允许读和写,如果文件存在则重写 “ab+ 读写打开或建立一个二进制文件,允许读取整个文件,或在文件术追加数据 说明 (1)文件打开方式由r、w、a、t、b、+六个字符拼成,含义如下。 ·r(read: 。w(write): 写 ·a(append): 追加 t(text): 文本文件,可省路不写 ·b(banary): 二进制文件 。+: 读和写 (2)用“”打开一个文件时,该文件必须己经存在,且只能从该文件读出信息。 (3)用“w”打开的文件只能向该文件写入。若打开的文件不存在,则以指定的文件 名建立该文件,若打开的文件已经存在,则将该文件删去,重建一个新文件。 (4)用“a”打开一个文件,若文件已存在,则在文件末尾追加新的信息。以追加方式 打开文件时,文件位置指针自动指向文件末尾。若文件不存在,则重建一个文件。 无论采用哪种打开方式,程序成功地打开一个文件后,fopen(0函数返回一个文件指针 其他I/O函数用这个指针来指定该文件。文件指针(比如这个例子中的)是一种指向 FLE的指针。指针并不指定实际的文件,而是一个关于文件信息的数据包,其中包括 文件/O使用的缓仲区信息。 因为标准库中的O函数使用缓冲区,所以它们需要知道缓冲区的位置,还需要知道 缓冲区的当前缓冲能力以及所使用的文件,这样这些函数在必要的时候可以再次填充或者 清空缓冲区。指向的数据包中包含全部这些信息。 在打开一个文件时,如果出错,fopen函数返回一个空指针值NULL。据此在程序中可 以判断是否能顺利打开文件。例如: if((fp=fopen("c:\\filel.dat","rb"))==NULL) printf("\n error on open c:\filel.dat !") exit(1) 4
4 表 12-3 文件打开方式及其含义 文件打开方式 含 义 “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”打开一个文件,若文件已存在,则在文件末尾追加新的信息。以追加方式 打开文件时,文件位置指针自动指向文件末尾。若文件不存在,则重建一个文件。 无论采用哪种打开方式,程序成功地打开一个文件后,fopen() 函数返回一个文件指针, 其他 I/O 函数用这个指针来指定该文件。文件指针 (比如这个例子中的 fp) 是一种指向 FILE 的指针。指针 fp 并不指定实际的文件,而是一个关于文件信息的数据包,其中包括 文件 I/O 使用的缓冲区信息。 因为标准库中的 I/O 函数使用缓冲区,所以它们需要知道缓冲区的位置,还需要知道 缓冲区的当前缓冲能力以及所使用的文件,这样这些函数在必要的时候可以再次填充或者 清空缓冲区。fp 指向的数据包中包含全部这些信息。 在打开一个文件时,如果出错,fopen 函数返回一个空指针值 NULL。据此在程序中可 以判断是否能顺利打开文件。例如: if((fp=fopen("c:\\file1.dat","rb"))==NULL) { printf("\n error on open c:\file1.dat !"); exit(1);

程序含义:如果返回的指针为空,则不能正确打开C盘根目录下的ll.dat文件,给 出提示信息“error on open c:\filel.dat!”,退出程序。 磁盘已满,文件名非法,存取权限不够或者硬件问题等都会导致fopen()函数执行失 败。 x)函数关闭所有打开的文件并终止程序。在使用xiO函数时村,通常的约定是正常 终止的程序传递值0,非正常终止的程序传递非0值,不同的退出值可以用来标识导致程 序失败的不同原因。 按照ANSIC,在最初调用的main(中使用return0和调用exit(0)的效果相同。两 者的区别是:如果main)在一个递归程序中,exit0仍然会终止程序:但return将控制权 移交给递归的前一级,直到最初的那一级,此时return才会终止程序。 12.3.2文件关闭函数(fclose) 文件使用完毕,应该关闭文件,断开文件指针与文件之间的联系,同时根据需要刷新 缓冲区。fclose函数调用的一般形式为: fc1o3e(文件指针): 例如: fclose(fp); 说明:正常关闭文件操作,fclose函数返回值为0:如返回非零值,则表示有错误发 生。 12.4文本文件的读写 对文件的读和写是最常用的文件操作,C语言中提供了多种文件读写函数,使用文件 操作函数都要求包含头文件stdio.h。 12.4.1字符读写函数(getc和putc) 前面章节中的每个/O函数都存在一个相似的文件/O函数,主要的区别在于你需要 使用一个FLE指针来为这些新函数指定要操作的文件。与getchar(和putchar(相似,字符 读写函数getc0和fputc()以字符(字节)为单位,每次可从文本文件读出或写入一个字符, 不同之处在于你需要告诉fgetc(和fpute(0函数他们要使用的文件。 1.字符读函数(fgete) 格式:字符变量=getc(文件指针): 功能:从指定的文件中读一个字符 5
5 } 程序含义:如果返回的指针为空,则不能正确打开 C 盘根目录下的 file1.dat 文件,给 出提示信息“error on open c:\file1.dat !”,退出程序。 磁盘已满,文件名非法,存取权限不够或者硬件问题等都会导致 fopen() 函数执行失 败。 exit() 函数关闭所有打开的文件并终止程序。在使用 exit()函数时,通常的约定是正常 终止的程序传递值 0,非正常终止的程序传递非 0 值,不同的退出值可以用来标识导致程 序失败的不同原因。 按照 ANSI C,在最初调用的 main() 中使用 return 0 和调用 exit(0) 的效果相同。两 者的区别是:如果 main() 在一个递归程序中,exit()仍然会终止程序;但 return 将控制权 移交给递归的前一级,直到最初的那一级,此时 return 才会终止程序。 12.3.2 文件关闭函数(fclose) 文件使用完毕,应该关闭文件,断开文件指针与文件之间的联系,同时根据需要刷新 缓冲区。fclose 函数调用的一般形式为: fclose(文件指针); 例如: fclose(fp); 说明:正常关闭文件操作,fclose 函数返回值为 0;如返回非零值,则表示有错误发 生。 12.4 文本文件的读写 对文件的读和写是最常用的文件操作,C语言中提供了多种文件读写函数,使用文件 操作函数都要求包含头文件 stdio.h。 12.4.1 字符读写函数(fgetc 和 fputc) 前面章节中的每个 I/O 函数都存在一个相似的文件 I/O 函数,主要的区别在于你需要 使用一个 FILE 指针来为这些新函数指定要操作的文件。与 getchar()和 putchar()相似,字符 读写函数 fgetc()和 fputc()以字符(字节)为单位,每次可从文本文件读出或写入一个字符, 不同之处在于你需要告诉 fgetc()和 fputc() 函数他们要使用的文件。 1.字符读函数(fgetc) 格式:字符变量=fgetc(文件指针); 功能:从指定的文件中读一个字符

例如: ch=fgetc(Ep):/从打开的文件p中读取一个字符并存入ch中 说明: (1)在fgetc函数调用前,文件必须是以读或读写方式打开的。 (2)读取字符的结果也可以不向字符变量赋值。例如: fgetc(fp); /读出的字符不保存 (3)在文件内部有一个位置指针,用于指向文件的当前读写字节:在文件打开时,该 指针总是指向文件的第一个字节:使用fgtc函数后,该位置指针向后移动一个字节:因 此可连续使用fgete函数,读取多个字符。 注意:文件指针和文件内部的位置指针不同。文件指针是指向整个文件的,须在程序 中定义说明,只要不重新赋值,文件指针的值是不变的:文件内部的位置指针用于指示文 件内部的当前读写位置,每读写一次,该指针均向后移动,它不需要在程序中定义说明, 由系统自动设置。 2.字符写函数(putc) 格式:fputc(字符,文件指针): 功能:把一个字符写入指定的文件中。 说明: (1)待写入的字符可以是字符常量或变量。例如: fpute('a',p):/是把字符'a'写入fp所指文件中 (2)被写入的文件可以用写、追加方式打开,用写方式打开一个已存在的文件时将清 除原有的文件内容,写入字符从文件首部开始:如需要保留原有文件内容,希望写入的字 符在文件末尾存放,必须以追加方式打开文件。 (3)每写入一个字符,文件内部位置指针向后移动一个字节。 【例12.1】从键盘输入一行字符,写入文本文件中,再从文本文件读出字符显示在幕上。 程序知下: #include int main ( FILE *fpin,*fpout char ch; if((fpin-fopen("d:\\cl.txt","wt"))=-NULL) printf("Cannot open file strike any key exit!"); return;/也可以用exit(1)终止程序 printf("input a string:\n"): ch-getchar(); /从键盘输入第一个字符 6
6 例如: ch=fgetc(fp); // 从打开的文件 fp 中读取一个字符并存入 ch 中 说明: (1)在 fgetc 函数调用前,文件必须是以读或读写方式打开的。 (2)读取字符的结果也可以不向字符变量赋值。例如: fgetc(fp); // 读出的字符不保存 (3)在文件内部有一个位置指针,用于指向文件的当前读写字节;在文件打开时,该 指针总是指向文件的第一个字节;使用 fgetc 函数后,该位置指针向后移动一个字节;因 此可连续使用 fgetc 函数,读取多个字符。 注意:文件指针和文件内部的位置指针不同。文件指针是指向整个文件的,须在程序 中定义说明,只要不重新赋值,文件指针的值是不变的;文件内部的位置指针用于指示文 件内部的当前读写位置,每读写一次,该指针均向后移动,它不需要在程序中定义说明, 由系统自动设置。 2.字符写函数(fputc) 格式:fputc(字符,文件指针); 功能:把一个字符写入指定的文件中。 说明: (1)待写入的字符可以是字符常量或变量。例如: fputc('a',fp); // 是把字符'a'写入 fp 所指文件中。 (2)被写入的文件可以用写、追加方式打开,用写方式打开一个已存在的文件时将清 除原有的文件内容,写入字符从文件首部开始;如需要保留原有文件内容,希望写入的字 符在文件末尾存放,必须以追加方式打开文件。 (3)每写入一个字符,文件内部位置指针向后移动一个字节。 【例 12.1】 从键盘输入一行字符,写入文本文件中,再从文本文件读出字符显示在幕上。 程序如下: #include int main() { FILE *fpin,*fpout; char ch; if((fpin=fopen("d:\\c1.txt","wt"))==NULL) { printf("Cannot open file strike any key exit!"); return ; //也可以用 exit(1)终止程序 } printf("input a string:\n"); ch=getchar(); // 从键盘输入第一个字符

while(ch!='\n') fputc(ch,fpin) /将ch中的字符写入fpin指向的文件 ch=getchar(); /1从键盘输入下一个字符 fclose(fpin); if((fpout=fopen("d:\\c1.txt","rt"))==NULL) printf("\nCannot open file !") return ch=fgetc(fpout) /将文件的第一个字符读入ch中 while(ch!=EOF) 1字符ch 不是 文件结束标志 putchar (ch); ch=fgetc(fpout) /将文件的当前字符读入ch中 fclose(fpout); return 0; 1 在C标准函数库中,字符EOF(stdio.h中这个定义#define EOF(l)表示文件结束符(end off们e)。在while循环中以EOF作为文件结束标志,这种以EOF作为文件结束标志的文件, 必须是文本文件。在文本文件中,数据都是以字符的ASCI代码值的形式存放。我们知道, ASCⅡ代码值的范形是0255,不可能出现-1,因此可以用EOF作为文件结束标志。所以 上例中输出文件指针中的内容时用while(chl=EOF)来表示控制循环。 当然我们也可以在不确定循环的次数时使用OF来控制循环的结束,例如: while(scanf(%d%d",&m,&n)l=EOF)。EOF的输入因系统而定,windows下是ctrl+z linux/unix下是ctrl+d。 12.4.2字符串读写函数(fgets和fputs) 1.读字符串函数(fgets) gets0函数只接受一个参数,而gets0函数接受3个参数。gets0函数的第一个参数 和gets0函数一样,是用于存储输入的地址(char*类型):第二个参数为整数,表示输入 字符串的最大长度:最后一个参数是文件指针,指向要读取的文件。 格式:fgCt5(字符数组名,n,文件指针): 功能:从指定的文件中读一个字符串存入字符数组中。 说明:n表示从文件中读出的字符串不超过n1个字符,在读入的最后一个字符后自 动加上字符串结束标志0。例如: fgets(stx,n,fp):/从fp所指的文件中读出n-1个字符存入字符数组str中. 7
7 while (ch!='\n') { fputc(ch,fpin); // 将 ch 中的字符写入 fpin 指向的文件 ch=getchar(); // 从键盘输入下一个字符 } fclose(fpin); if((fpout=fopen("d:\\c1.txt","rt"))==NULL) { printf("\nCannot open file !"); return ; } ch=fgetc(fpout); // 将文件的第一个字符读入 ch 中 while(ch!=EOF) // 字符 ch 不是文件结束标志 { putchar(ch); ch=fgetc(fpout); // 将文件的当前字符读入 ch 中 } fclose(fpout); return 0; } 在 C 标准函数库中,字符 EOF(stdio.h 中这个定义#define EOF (-1)表示文件结束符(end of file)。在 while 循环中以 EOF 作为文件结束标志,这种以 EOF 作为文件结束标志的文件, 必须是文本文件。在文本文件中,数据都是以字符的 ASCII 代码值的形式存放。我们知道, ASCII 代码值的范围是 0~255,不可能出现-1,因此可以用 EOF 作为文件结束标志。所以 上例中输出文件指针中的内容时用 while(ch!=EOF)来表示控制循环。 当然我们也可以在不确定循环的次数时使用 EOF 来控制循环的结束,例如: while(scanf("%d%d", &m, &n)!= EOF)。EOF 的输入因系统而定,windows 下是 ctrl+z, linux/unix 下是 ctrl+d。 12.4.2 字符串读写函数(fgets 和 fputs) 1.读字符串函数(fgets) gets() 函数只接受一个参数,而 fgets() 函数接受 3 个参数。fgets() 函数的第一个参数 和 gets() 函数一样,是用于存储输入的地址 (char *类型);第二个参数为整数,表示输入 字符串的最大长度;最后一个参数是文件指针,指向要读取的文件。 格式:fgets(字符数组名,n,文件指针); 功能:从指定的文件中读一个字符串存入字符数组中。 说明:n 表示从文件中读出的字符串不超过 n-1 个字符,在读入的最后一个字符后自 动加上字符串结束标志'\0'。例如: fgets(str,n,fp); // 从 fp 所指的文件中读出 n-1 个字符存入字符数组 str 中

【例12.2】从c1.t文件中读出一个含10个字符的字符串显示在屏幕上。 程序如下: #include int main() FILE *fp: char str[11]; if((fp=fopen("d:\\cl.txt","rt"))==NULL) /以读文本文件方式打开文件 printf("\ncannot open file strike any key exit!"); return fgets(str,11,fp); /从印所指的文件中读入一个含10个字符的字符申赋给st printf("8s\n",str): fclose(fp): return 0; 1 程序分析:定义字符数组st,以读文本文件方式打开d盘上文件cl.tt,从cl.tt中 读出10个字符送入st数组,自动在数组最后将加上0,然后在屏幕上显示输出5r数组。 对gets函数有两点说明: (1)在读出1个字符之前,如遇到了换行符或文件结束符,则读出结束。 (2)gcts函数的返回值是字符数组的首地址。 2.写字符串函数(fputs) pus0函数接受两个参数,它们依次是一个字符串的地址和一个文件指针,它把字符 串地址指针所指的字符串写入指定文件。与put0函数不同,puts0函数打印的时候并不 添加一个换行符 格式:fputs(字符串,文件指针): 功能:向指定的文件写入一个字符串 说明:字符串可以是字符串常量、字符数组名、字符指针变量。例如: fputs("abcd",fp); /把字符串“abcd”写入fp所指的文件之中。 【例12.3】在文件cl.xt中追加一个字符串。 Winclude int main() FILE *fp; char ch; char st[20]; if((fp=fopen("d:\\cl.txt","at+"))=-NULL) /以追加方式打开文件 8
8 【例 12.2】 从 c1.txt 文件中读出一个含 10 个字符的字符串显示在屏幕上。 程序如下: #include int main() { FILE *fp; char str[11]; if((fp=fopen("d:\\c1.txt","rt"))==NULL) // 以读文本文件方式打开文件 { printf("\nCannot open file strike any key exit!"); return ; } fgets(str,11,fp); // 从 fp 所指的文件中读入一个含 10 个字符的字符串赋给 str printf("%s\n",str); fclose(fp); return 0; } 程序分析:定义字符数组 str,以读文本文件方式打开 d 盘上文件 c1.txt,从 c1.txt 中 读出 10 个字符送入 str 数组,自动在数组最后将加上'\0',然后在屏幕上显示输出 str 数组。 对 fgets 函数有两点说明: (1)在读出 n-1 个字符之前,如遇到了换行符或文件结束符,则读出结束。 (2)fgets 函数的返回值是字符数组的首地址。 2.写字符串函数(fputs) fputs() 函数接受两个参数,它们依次是一个字符串的地址和一个文件指针,它把字符 串地址指针所指的字符串写入指定文件。与 puts() 函数不同,fputs() 函数打印的时候并不 添加一个换行符。 格式:fputs(字符串,文件指针); 功能:向指定的文件写入一个字符串。 说明:字符串可以是字符串常量、字符数组名、字符指针变量。例如: fputs("abcd",fp); // 把字符串“abcd”写入 fp 所指的文件之中。 【例 12.3】 在文件 c1.txt 中追加一个字符串。 #include int main() { FILE *fp; char ch; char st[20]; if((fp=fopen("d:\\c1.txt","at+"))==NULL) // 以追加方式打开文件 {

printf("Cannot open file strike any key exit!"); return printf("input a string:\n"); scanf("s fputs (st,fp) /将t表示的字符串追加到p所指的文件中 fclose(fp); return 0; 程序分析:以追加读写文本文件的方式打开d盘文件cl.xt,输入字符串并用pus函 数把该字符串写入文件cl.wt末尾。 12.4.3格式化读写函数(fscanf和fprintf) fscanf函数和fprintf函数与scanf和printf函数的功能相似,都是格式化读写函数。两 者的区别在于fscanf函数和fprintf函数的读写对象不是键盘和显示器,而是磁盘文件。 格式: fscanf(文件指针,格式字符串,输入表列): fprintf(文件指针,格式字符串,输出表列): 含义: fscanf()表示从文件指针所指文件中读取数据到输出编列: fprintf()表示将输出表列数据写入到文件指针所指文件中 例如: fscanf(fp,"ds“,i,s):/从fp所指文件读取数据到变量i和s中 fprintf(fp,"gdc",j,ch):/将变量j和ch的值写入到fp所指文件中 【例12.4】创建一个文件并向文件中加入单词,然后输出文件内容。用fscanf和fprintf 操作。 程序如下: #include #include detine MAX 30 int main() FILE *ED: char words[MAX】,words1【MAX】: if((fp=fopen("d:\\fwords","at+"))==NULL) ("c file !" 9
9 printf("Cannot open file strike any key exit!"); return ; } printf("input a string:\n"); scanf("%s",st); fputs(st,fp); // 将 st 表示的字符串追加到 fp 所指的文件中 fclose(fp); return 0; } 程序分析:以追加读写文本文件的方式打开 d 盘文件 c1.txt,输入字符串并用 fputs 函 数把该字符串写入文件 c1.txt 末尾。 12.4.3 格式化读写函数(fscanf 和 fprintf) fscanf 函数和 fprintf 函数与 scanf 和 printf 函数的功能相似,都是格式化读写函数。两 者的区别在于 fscanf 函数和 fprintf 函数的读写对象不是键盘和显示器,而是磁盘文件。 格式: fscanf(文件指针,格式字符串,输入表列); fprintf(文件指针,格式字符串,输出表列); 含义: fscanf()表示从文件指针所指文件中读取数据到输出编列; fprintf()表示将输出表列数据写入到文件指针所指文件中 例如: fscanf(fp,"%d%s",&i,s); //从 fp 所指文件读取数据到变量 i 和 s 中 fprintf(fp,"%d%c",j,ch); //将变量 j 和 ch 的值写入到 fp 所指文件中 【例 12.4】创建一个文件并向文件中加入单词,然后输出文件内容。用 fscanf 和 fprintf 操作。 程序如下: #include #include #define MAX 30 int main() { FILE *fp; char words[MAX],words_1[MAX]; if((fp=fopen("d:\\fwords", "at+")) == NULL) { printf("Cannot open file !"); exit(1) ; //结束程序

printf("Enter words to add to the file,then press the Enter"): while (gets (words)!=NULL &6 words [0]!-\0') fprintf(Ep,"多s",words);/往fp所指向的文件中写入i一个单词 puts("file contents :") wind(fp); //回到文件的开始处 while(f canf(fp,"s",wo 1) =1)/从印所指文件读取一个单词到word3_】 puts(words_1);/输出单词 fclose(fp); return 0; 运行结果: Enter words to add to the file,then press the Enter I am a student file contents student 再运行一遍 Enter words to add to the file,then press the Enter I am a student file contents 20 student I am student 程序分析:在本程序中,通过printf函数向文件中加入单词。每次只读写一个单词, 因此采用了循环语句来读写全部单词。 该程序使用"t+"模式,程序口以对文件进行读写架作。第一次使用该程序的时候会创 建一个fods文件以添加单词。在随后的使用中,可以向以前的内容后面添加(追加)单 词。追加模式只能向文件结尾添加内容,但"at+"模式可以读取整个文件。rewind()命令使 程序回到文件开始处,这样最后的while循环就可以通过fscanf)和puts()读取打印文件的 内容。注意rewind()i函数接受一个文件指针参数。 12.5二进制文件的读写 12.5.1二进制模式与文本模式的区别 10
10 } printf("Enter words to add to the file,then press the Enter"); while (gets(words) != NULL && words[0] != '\0') fprintf (fp, "%s", words); //往 fp 所指向的文件中写入 i 一个单词 puts("file contents :"); rewind(fp); //回到文件的开始处 while(fscanf(fp, "%s", words_1) == 1)//从 fp 所指文件读取一个单词到 words_1 puts (words_1); //输出单词 fclose(fp); return 0; } 运行结果: Enter words to add to the file,then press the Enter I am a student file contents : I am a student 再运行一遍: Enter words to add to the file,then press the Enter I am a student file contents : I am a student I am a student 程序分析:在本程序中,通过 fprintf 函数向文件中加入单词。每次只读写一个单词, 因此采用了循环语句来读写全部单词。 该程序使用"at+"模式,程序可以对文件进行读写操作。第一次使用该程序的时候会创 建一个 fwords 文件以添加单词。在随后的使用中,可以向以前的内容后面添加 (追加) 单 词。追加模式只能向文件结尾添加内容,但"at+"模式可以读取整个文件。rewind()命令使 程序回到文件开始处,这样最后的 while 循环就可以通过 fscanf()和 puts()读取打印文件的 内容。注意 rewind()函数接受一个文件指针参数。 12.5 二进制文件的读写 12.5.1 二进制模式与文本模式的区别