本节重点讲解ANSI C文件库。包括文件指针的概念;文件和流之间的关系;文本和二进制文件;和文件的基本操作。ANSI的C标准文件库封装了文件的系统调用,为了提高效率还加入了文件缓冲机制,提供记录的方式读写文件,并且具有良好的可移植性和健壮性,是Linux C语言最基本的文件编程。
1.文件指针和流
件是可以永久存储的,有特定顺序的一个有序,有名称的字节组成的集合。在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;
2.存储方式
ANSI C规定了两种文件的存储方式:文本方式和二进制方式。文本文件也称作ASCII文件,每个自己存储一个ASCII码字符,文本文件存储量大,便于对字符操作,但是操作速度慢;二进制文件降数据按照内存中的存储形式存放,二进制文件的存储量小,存取速度快,适合存放中间结果。
在Linux系统上,文件的存放都是按照二进制方式存储的,用户在打开的时候,根据用户指定的打开方式进行存取。
3 .标准输入,标准输入和标准错误
Linux系统为每个进程定义了标准输入、标准输出和标准错误三个文件流,也称作I/O数据流。系统预定义的三个文件流有固定的名称,因此无需创建可以直接使用。stdin是标准输入,默认是从键盘读取数据;stdout是标准输出,默认向屏幕输出数据;stderr是标准错误,默认是向屏幕输出数据。
三个I/O数据流定义在stdio.h头文件里,程序在使用前需要引用相关头文件。C标准库函数printf()默认使用stdout输出数据,用户也可以通过重新设置标准I/O,把程序的输入输出结果定向到其他设备。
4 缓冲
标准文件I/O库提供了缓冲机制,目的是为了减少外部设备的读写次数。同时,使用缓冲也能提高应用程序的读写性能。标准文件I/O提供了三种类型的缓冲:
- 全缓冲。
- 行缓冲。
- 不带缓冲。
打开关闭文件
ANSI C文件库定义了打开文件函数fopen()和关闭文件函数fclose(),定义如下: FILE *fopen(const char *path, const char *mode); int fclose(FILE * stream);
mode参数说明
- r或rb为
读打开文件 - w或wb
为写打开文件,并把文件长度置为0(清空文件) - a或ab
在文件结尾添加打开 - r+或r+b或rb+
为读和写打开 - w+或w+b或wb+
为写打开文件,并把文件长度置0(清空文件) - a+或a+b或ab+
在文件结尾读写打开
6 读写文件
一但成功打开一个文件后,就可以进行文件操作了,ANSI C文件库提供了三种不同类型的文件读写函数:
- 每次一个字符的I/O。
- 每次一行的I/O。
- 成块数据的I/O。
1.每次一个字符的文件读写函数
下面三个函数可以一次读一个字符,函数定义如下:
int getc(FILE *stream); int fgetc(FILE *stream); int getchar(void);
2.每次一行的文件读写函数
每次读取一行的文件I/O函数,定义如下:
char *fgets(char *s, int size, FILE *stream); char *gets(char *s);
3.成块数据的文件读写函数
这时就需要使用成块数据的读写函数,定义如下:
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);
7 文件流定位
在读写文件的时候每个文件流都会维护一个文件流指针,表示当前文件流的读写位置,在打开文件的时候文件流指针位于文件的最开头(使用‘a’方式打开的文件,文件流指针位于文件最后),当读写文件流的时候,读写文件流的函数会不断改变文件流当前位置。当用户在写入一些数据后,如果需要读取之前写入的数据,或者需要修改指定文件位置的数据,就需要用到文件流定位功能。为此,ANSI文件I/O库提供了文件流定位函数,定义如下:
int fseek(FILE *stream, long offset, int whence); long ftell(FILE *stream); void rewind(FILE *stream);
8 ANSI C文件编程实例
在本节最后,给出一个文件编程实例,打开一个文件,向文件写入三个字符串,然后重新定位文件流读写指针到文件起始位置,从文件读取刚写入的三个字符串到另一个缓冲,并且打印读出来的字符串。
#include <stdio.h> 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+"); // 使用读写方式打开文件,并且把文件长度置0 if (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; }