标准I/O及文件操作

对文件的操作有两个级别,通过操作系统提供基本I/O服务的系统级I/O和通过C语言标准库函数提供的标准I/O。实际上标准I/O就是被封装的系统级I/O对外提供的接口,我们同样可以自己去定义实现符合自己需求的I/O标准库。

至于什么才是文件,在操作系统中已经有了初步的概念。实际上在*NIX系统下,除了我们狭义认识的那些文件外,任何外设都被看成是文件,这样的设计简化了很多不必要的麻烦,对所有设备的操作都有统一的方式。

C程序会自动打开三个文件,他们分别是标准输入(stdin),标准输出(stdout)和标准错误输出(stderr)。这三个文件是默认打开的,不需要我们单独做处理。但是如果我们的程序是要对其他文件进行处理时,首先需要做的就是打开文件,我们先抛开其中的细节,以读模式打开文件,具体的操作方式如下:

FILE *fp = fopen(“filename”, “r”);

解读这条语句首先要清楚变量fp指针指向的是什么类型的数据,之前就说到,标准I/O库封装了底层的实现,所以其实FILE本质是一个结构体,每一个FILE变量都是包含文件信息的数据对象,其中包含被操作文件的缓冲区信息(标准库函数中的I/O使用缓冲区),缓冲区被填充程度等。更清晰的理解就是fp指针指向了一个结构体变量,该变量包含诸多待操作文件的索引和信息。

C语言标准I/O库里,提供给程序员打开一个文件的接口就是fopen,它封装了系统级层面打开一个文件的细节,包括如何初始化FILE结构体基本信息等。在fopen中文件名部分如果打开的文件和源文件在同一个文件夹只需要输入文件名即可,否则需要给出完整的路径。当fopen函数参数中所写的文件能够按照给定的方式正确打开的话,fopen就会返回一个指向创建成功的FILE结构的一个指针给fp,此时完成对文件的打开,接下来对于文件的任何操作都需要通过fp来完成。当然,如果文件打开失败就会返回NULL

这个时候在程序中就可以同时对4个已经打开的文件进行操作,保存这四个打开文件信息的结点分别被stdinstdoutstderrfp做指向。接下来就可以将文件中的数据互相“搬运”和操作了。

标准I/O库中包含的函数很多,这里不可能一一举例说明他们的用途。但本质上其实就只有三种操作模式:单文件内容读取至内存,操作后写入文件(或不改变);从file1中读取文件操作并写入file2

总体来说就是三大步骤:读取、操作、定向。

在这三个步骤中,文件的操作建立在第一步读取完成之上,所有对数据的操作首先必须数据存在于内存中,所以我们可以在函数中定义新的内存变量来接收从文件中取出(实际上是从文件缓冲区将内容拷贝到定义的临时变量中)的数据,然后采用常规的对内存数据的操作方式,最后将处理完的数据重新写入需要存入的文件中。关闭文件时,系统会刷新缓冲区将新的内容写入磁盘文件。

读取类:

int getc(int ch, FILE *stream);

char* fgets(char *buf, int bufsize, FILE *stream);

int fscanf(FILE *stream, const char *format, [argument…]);

getc函数的作用是在数据流中取字。fgetsfscanf最大的区别在于fscanf遇到空格和换行时结束,fgets遇到空格时不结束。

定向类:

int putc(int ch, FILE *stream);

char *fputs(char *buf, FILE *stream);

int fprintf(FILE *stream, const char *format, [argument…]);

同样的,相比于fputsfprintf最大的区别在于遇到字符串结束标志就会停止。

另外补充的内容也是文件处理中非常常用的两个函数fseekftell。有了fseek便可以将文件看做一个大的数组,在fopen打开的文件中移动到任意字节处。ftell返回的是当前当前访问的位置。

定位类:

long ftell(FILE *stream);

int fseek(FILE *stream, int offset, int where);

其中fseek的三个参数分别是文件流指针,相对于where位置的偏移量(可正可负)以及初始位置。

最后,文件操作不要忘了fclose,其作用是把缓冲区内容写入内核缓冲区,释放文件指针和有关的缓冲区。若成功关闭返回0,否则返回EOF

      

 

      

Advertisements