本节重点讲解ANSI C文件库。包括文件指针的概念;文件和流之间的关系;文本和二进制文件;和文件的基本操作。ANSI的C标准文件库封装了文件的系统调用,为了提高效率还加入了文件缓冲机制,提供记录的方式读写文件,并且具有良好的可移植性和健壮性,是Linux C语言最基本的文件编程。
件是可以永久存储的,有特定顺序的一个有序,有名称的字节组成的集合。在Linux系统中,通常能见到的目录、设备文件和管道等,都属于文件,具有不同的特性。本节描述的ANSI文件只能用于普通文件操作。
ANSI文件操作提供了一个重要的结构-文件指针FIL。文件的打开、读写和关闭以及其他访问都要通过文件指针完成。FILE结构通常作为FILE*的方式使用,因此被称作文件指针,这个结构在stdio.h头文件的定义:
typedef struct {int level; unsigned flags; char fd; unsigned char hold;
int bsize; unsigned char _FAR *buffer; unsigned char _FAR *curp; unsigned istemp;short token; } FILE;
ANSI C规定了两种文件的存储方式:文本方式和二进制方式。文本文件也称作ASCII文件,每个自己存储一个ASCII码字符,文本文件存储量大,便于对字符操作,但是操作速度慢;二进制文件降数据按照内存中的存储形式存放,二进制文件的存储量小,存取速度快,适合存放中间结果。
在Linux系统上,文件的存放都是按照二进制方式存储的,用户在打开的时候,根据用户指定的打开方式进行存取。
Linux系统为每个进程定义了标准输入、标准输出和标准错误三个文件流,也称作I/O数据流。系统预定义的三个文件流有固定的名称,因此无需创建可以直接使用。stdin是标准输入,默认是从键盘读取数据;stdout是标准输出,默认向屏幕输出数据;stderr是标准错误,默认是向屏幕输出数据。
三个I/O数据流定义在stdio.h头文件里,程序在使用前需要引用相关头文件。C标准库函数printf()默认使用stdout输出数据,用户也可以通过重新设置标准I/O,把程序的输入输出结果定向到其他设备。
标准文件I/O库提供了缓冲机制,目的是为了减少外部设备的读写次数。同时,使用缓冲也能提高应用程序的读写性能。标准文件I/O提供了三种类型的缓冲:
ANSI C文件库定义了打开文件函数fopen()和关闭文件函数fclose(),定义如下:
FILE *fopen(const char *path, const char *mode);
int fclose(FILE * stream);
mode参数说明
一但成功打开一个文件后,就可以进行文件操作了,ANSI C文件库提供了三种不同类型的文件读写函数:
下面三个函数可以一次读一个字符,函数定义如下:
int getc(FILE *stream);
int fgetc(FILE *stream);
int getchar(void);
每次读取一行的文件I/O函数,定义如下:
char *fgets(char *s, int size, FILE *stream);
char *gets(char *s);
这时就需要使用成块数据的读写函数,定义如下:
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
在读写文件的时候每个文件流都会维护一个文件流指针,表示当前文件流的读写位置,在打开文件的时候文件流指针位于文件的最开头(使用‘a’方式打开的文件,文件流指针位于文件最后),当读写文件流的时候,读写文件流的函数会不断改变文件流当前位置。当用户在写入一些数据后,如果需要读取之前写入的数据,或者需要修改指定文件位置的数据,就需要用到文件流定位功能。为此,ANSI文件I/O库提供了文件流定位函数,定义如下:
int fseek(FILE *stream, long offset, int whence);
long ftell(FILE *stream);
void rewind(FILE *stream);
在本节最后,给出一个文件编程实例,打开一个文件,向文件写入三个字符串,然后重新定位文件流读写指针到文件起始位置,从文件读取刚写入的三个字符串到另一个缓冲,并且打印读出来的字符串。
#include
int main(){FILE *fp = NULL; // 定义文件指针char *buf[3] = { // 定义三个字符串,供写入文件使用"This is first line!\n","Second Line!\n","OK, the last line!\n"};char tmp_buf[3][64], *p; // 定义字符串缓存,供读取文件使用int i;fp = fopen("chap7_demo.dat", "rb+"); // 使用读写方式打开文件,并且把文件长度置0if (NULL==fp) {printf("error to open file!\n");return -1;}// 把三个字符串写入文件for (i=0;i<3;i++)fputs(buf[i], fp);fseek(fp, 0, SEEK_SET); // 把文件指针设置到文件开头,相当于rewind(fp)// 从文件读取三个字符串到缓存for (i=0;i<3;i++) {p = tmp_buf[i];fgets(p, 64, fp);printf("%s", p); // 打印刚读取出来的字符串到屏幕}fclose(fp); // 别忘记关闭文件return 0;
}