# 文件是什么
文件是指一组相关数据的有序集合,这个数据集有一个名称叫做文件名。文件可以是自己编制的,也可以是系统已有的。事实上我们已经多次使用了文件,例如源程序文件,目标文件、可执行文件、库文件等。
为了将结果保存起来,就需要使用文件。将数据以文件的形式存放在光盘、磁盘等外存储器上,可以达到重复利用、永久保存数据的目的。文件可分为普通文件和设备文件两种。通常吧显示器定义为标准输出文件,一般情况下在屏幕上显示有关信息就是向标准输出文件输出。如前面经常使用的 printf、putchar 函数就是这类输出。键盘通常被指定标准的输入文件,从键盘上输入意味着以标准输入文件输入数据。scanf、getchar 函数就属于这类输入。
# 文件类型
文件可分为 ASCII 码文件和二进制文件两种。ASCII 文件也成为文本文件,这种文件在磁盘中存放时每个字符对应一个字节,用于存放对应的 ASCII 码。
例如数 6843 的存储形式为:
ASCII 码:00110110 00111000 00110100 00110011
十进制码: 6 8 4 3
共占用四个字节。
ASCII 码文件可在屏幕上按字符显示,例如源程序文件就是 ASCII 文件,用 DOS 命令 TYPE 可显示文件的内容。
二进制文件是按二进制编码的方式来存放文件的。例如,数 6843 的存储形式为:00011010 10111011
只占两个字节。二进制文件也可以在屏幕中显示,但内容无法读懂。
输入输出字符流的开始和结束只由程序控制而不受物理符号(如回车符)的控制。因此也把这种文件称作流式文件。
# 文件指针
在 C 语言中用一个指针变量指向一个文件,这个指针被称为文件指针,通过文件指针可以对它所指的文件进行各种操作。存放文件的有关信息被保存在一个结构体变量中,它是由系统定义的,取名为 FILE。在编写源程序时不必关心 FILE 结构的细节。例如:
1 | FILE * 指针变量标识符 |
其中 FILE 必须为大写,该结构中含有文件名、文件状态和文件当前位置等信息。
注意:在操作系统中,文件被作为重要的系统资源来看待。因此,当程序需要访问文件时,程序员必须显式地打开某个文件,并在使用后关闭它。程序中所有对文件的操作都通过文件指针来实现。
# 文件打开操作
C 语言没有输入输出语句,对文件的读写都是用看库函数来实现的。
对文件进行操作时应遵循一下步骤:
- 打开文件。打开文件是指请求系统为指定文件分配内存缓冲区,建立文件的各种有关信息,文件使用前必须先打开。
- 读写文件。包括文件的读、写、定位等操作。
- 关闭文件。确保数据完整写入文件并释放内存缓冲区。
打开文件,实际上是建立文件的各种有关信息,并使文件指针指向该文件。关闭文件则是断开指针与文件之间的联系,也就是禁止再对该文件操作。
fopen 函数用来打开一个文件,其调用的一般形式为:
1 | 文件指针名 = fopen ( 文件名 , 使用文件方式 ) ; |
文件指针名必须是被说明为 FILE 类型的指针变量;文件名使被打开文件的文件名,可以是字符串常量或字符串数组;使用文件方式是指文件类型和操作要求。
例如:
1 | FILE * fp ; |
其意义使在当前目录下打开文件 file a,只允许进行读入操作,并使 fp 指向该文件。
又如:
1 | FILE * fp ; |
其意义是打开 C 驱动磁盘的根目录下的文件 test,这是一个二进制文件,只允许按二进制的方式进行读操作。两个反斜杠 "\" 第一个表示转义字符,第二个表示根目录。
或者使用:
1 | FILE * fopen ( const char * filename , const char * mode ) ; |
返回失败时返回空指针 NULL
使用文件的方式共有 12 种,下表给出其符号以及意义。
文件使用方式 | 意义 |
---|---|
r | 打开文件,只读 |
w | 打开或建立文件只写 |
a | 追加打开一个文本文件,并在文件末尾写数据 |
rb | 二进制文件,同上 |
wb | 二进制文件,同上 |
ab | 二进制文件,同上 |
r+ | 读 + 写 |
w+ | 读 + 写 |
a+ | 读 + 写 |
rb+&wb+&ab+ | 类推 |
总结如下:r (ead) , w (rite) , a (ppend) , t (ext) , b (inary) 。+:读和写
查看是否成功读入
1 | if ( ( fp = fopen ( "text" , "rb" ) ) == NULL ) { |
# 文件关闭操作
1 | FILE * fp ; |
关闭成功返回值为 0,否则为非零值
如果打开了多个文件且需要统一关闭:
1 | int fcloseall ( ) ; |
此函数关闭除了标准流意外的所有打开流,刷新所有的流缓冲区,并关闭返回的参数,否则返回 EOF。
标准流:stdin,stdout,stderr
# 文件结束检测
1 | int feof ( FLIE * fp ) ; |
文件未结束返回 0,已结束返回真。
# 文件错误检测函数
1 | int ferror ( FILE * fp ) ; |
发生错误返回非零,否则返回 0
# 定位文件位置指针函数
1 | fseek ( FILE * fp , long offset , int startpos ) ; |
offset 表示目标位置相对起始点的偏移量,要求偏移量为 long 型数据以便在文件长度大于 64KB 时不会出错,当用常量表示位移量时,要求加后缀 L.
startpos 表示从何处计算偏移量:SEEK_SET:0 , SEEK_CUR:1 , SEEK_END:2 ;
fseek 函数一般用于二进制文件,在文本文件中由于要进行转换,故往往会出现错误。
# 重置文件位置指针函数
1 | rewind ( FILE * fp ) ; |
移动到文件开始的位置。
无返回值
# 移动指针到当前位置函数
1 | long ftell ( FILE * p ) ; |
若函数调用成功则函数的返回值时当前读写位置偏离文件头部的字节数,否则返回 - 1 ;
文件的长度
1 | ftell ( fp , 0L , SEEK_END ) ; |
# 面向字符的文件读写操作
1 | fputc ( int c , FILE * stream ) ; |
c 是带写入的字符,可以是字符常量或者变量。
每写入一个字符,文件内部位置指针将向后移动一个字节。返回值为字符或者 EOF。
如果用写或者读写方式打开一个已存在的文件时将清除原有的文件内容,写入字符从文件首开始,如需保留原有文件内容,必须以追加的方式打开文件。
1 | ch = fgetc ( FILE * stream ) ; |
读取的文件必须是以读写或读的方式打开的。
# 面向字符串的文件读写操作
1 | char * fgets ( char * string , int n , FILE * stream ) ; |
函数的功能是从 stream 指向的文件中逐一读取 n-1 个字符,并将读取的字符保存到 string 指向的连续存储空间。
在读取 n-1 个字符之前如果遇到了换行符或 EOF,则读取结束。
1 | int fputs ( const char * string , FILE * stream ) ; |
执行成功返回非负整数,否则返回 EOF。不会把 \0 写入文件。
# 面向格式化输入输出的文件读写操作
1 | int fscanf ( FILE * stream , const char * format[,argument]...) ; |
返回值为读取正确的数据个数, EOF 为读取错误或文件结束。
1 | int fprintf ( FILE * stream , const char * format[,argument]... ) ; |
返回值为正确写入返回数据的个数,负值为读写错误。
# 面向信息块的文件读写操作
1 | fread ( void * buffer , int size , int count , FILE * fp ) ; |
例如:fread (fa , 4 , 5 , fp) ; 的意义是从 fp 所指的文件中,每次读 4 个字节,送入实数数组 fa 中,连续读 5 次。