vlambda博客
学习文章列表

C语言晋级--ANSI C文件管理


本篇文章的重点是理解ANSI C文件库,包括文件指针的概念;文件和流之间的关系;文本和二进制文件;文件的基本操作。ANSI 的 C 的标准库封装了文件的系统调用,为了提高文件打开的效率还加入了缓冲机制,提供记录的形式读写文件,并且有很好的移植性,是linux C语言最基础的文件编程。

一、文件指针和六流

文件:永久储存的、有特定顺序的、有名称的字节组成的集合。在Linux 系统中通常能见到的目录、设备文件、管道等都属于文件。
文件指针LILE:文件的打开、读写、关闭、以及其他访问都通过文件指针来完成,文件指针在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;

当我们打开一个文件时,会返回一个LILE文件指针,为我们以后的文件操作提供使用。在ANSI标准库中文件的操作都是围绕流(stream)进行的,流是一个抽象的概念。在程序开发中流常用来描述物质从一处向另一处的流动。
操作系统屏蔽了操作文件I/O和物理细节,当打开一个文件之后就把文件绑定在了一起,对用户而言操作文件只需要操作流,也就是操作文件的数据流即可。

二、储存方式

两种储存方式分别为:文本方式、二进制方式

文件方式: 又称为ASCII文件,每一个字符都是一个ASCII码,文本文件的储存量大,便由于对字符进行操作,但是操作速度较慢;

二进制方式:将数据按照内存中的储存形式形式存储形式进行存放,二进制文件的容量小,存储速度快,适合存放中间结果;

在Linux中文件是按照二进制的形式储存的,用户打开的时候根据用户指定的打开方式进行存取;

三、输出、输入

Linux为每个进程都定了标准输入、标准输出和标准错误三个文件流,也称I/O数据流,系统与定义的三个文件流都有自己固定的名称,因此无需创建可以直接使用。

stdin:标准输入,默认是从键盘上读取数据stdout:标准输出,默认向屏幕输出数据stderr:标准错误,默认向屏幕输出数据


3个I/O数据流定义在stdio.h头文件里,程序在运行之前需要引用相关的头文件。C语言的标准库函数printf()默认就是使用stdout输出数据的,用户也可以通过重新设置标准的I/O,把程序的输出输入结果定向到其他设备上。

四、缓冲

标准的文件I/O提供了缓冲机制,目的在于减少外部设备的读取次数,同时可以提高程序的读写性能,标准库提供了三种缓冲类型:

全缓冲:全缓冲通常用在磁盘文件中,只有当缓冲写满之后才会把缓冲的数据储存到磁盘中;

行缓冲:行缓冲顾名思义就是以行为单位操作缓冲区,使用这种缓冲方式当系统遇到换行符的时候会执行I/O操作,这是终端常用的缓冲模式;

不带缓冲:标准的I/O不缓冲任何字符。如果使用不带缓冲的流,相当于直接把数据通过系统调用写到设备上(后面会介绍write系统调用)如标准错误输出stderr就是不带缓冲的。

ANSI文件I/O库在stdio.h头文件中为用户提供了两个设置缓冲的函数接口:

void setbuf(FILE *fp, char *buf);int setvbuf(FILE *fp, char *buf, intmode, siez_t size);

setbuff()函数可以打开或者关闭一个I/O流使用缓冲。fp参数传入一个I/O流的文件指针,buf参数指向一个BUFSIZ(在stdio.h头文件中定义)大小的缓冲,在设置buf参数后标准库会为I/O流设置一个全缓冲。如关闭一个缓冲,设置buf参数为NULL即可;

举例:

#ininclude <stdio,h>char *buf = (char*)malloc(BUFSIZ);setbuf(stdout,buf);printf("Set STDOUT full buffer OK!\n");setbuf(stdout,NULL);printf("Set STDOUT no buffer OK!\n")

需要注意的是在设置一个文件的缓冲时需要打开文件才能设置

setbuff()函数是依靠mode参数来实现为I/O流设置指定类型的缓冲,mode的参数如下:

_IOFBF:全缓冲;_IOLBF:行缓冲;_IONBF:不带缓冲;

其中如果指定了不带缓冲,setbuf()函数会忽略buf和size参数;如果setbuf()函数的buf参数为空,mode参数在仍然设置全缓冲或者行缓冲时,库会自动为指定的流设置一个适当长度的缓冲;

五、打开关闭文件

ANSI C文件库定义了打开文件的函数fopen()和关闭文件的函数fclose(),定义如下:

FILE *FOPEN(const char *path, const char *mode); int fclose(FILE * stream);

打开关闭文件的函数都定义在stdio.h的头文件中,fopen()函数用来打开一个文件,path参数指定文件路径mode参数指定打开方式 fopen()参数如下:

mode参数 说明
r或rb 为读打开文件
w或wb 为写打开文件,并把文件长度置0(清空文件)
a或ab 在文件结尾添加打开
r+或r+或rb+ 为读和写打开
w+或w+b或wb+ 为写打开文件,并把文件大小置0(清空文件)
a+或a+b或ab+ 在文件结尾读写打开

在文件结尾读写打开mode参数将文件分为读、写、读写3种方式,另外参数中的+也有作用,表示在文件打开后在最后添加数据,这种方式不会破坏原来的文件内容当打开一个文件成功后fopen()函数会返回一个FILE类型的文件指针,这个指针是关键,后面的操作都需要用到。

如果文件打开失败,会返回NULL,这个可作为是否成功打开文件的判断依据;在操作完文件需要将打开的文件关掉,fclose函数关闭文件成功后会返回一0,如果关闭失败会返回常量EOF,并且设置错误代码到系统库的ERROR全局变量。

关闭文件不只是一种好的习惯,更重要的是文件流可能带有缓冲,只有成功关闭了文件以后才能确保数据被正确写入,否则可能造成数据丢失;

六、读写文件

一旦文件打开成功,我们就可以进行文件操作了,ANSI C 文件库提供了3种不同类型的文件读写函数:

1、每次一个字符的I/O。一次读写一个字符,如果需要带有缓冲的流,由标准I/O函数处理缓冲;

2、每次一行的I/O。每次读写一行的数据,换行符\n标志着一行的结束

3、成块数据的I/O。每次读写指定大小的数据,可以指定数据块的大小,以及数据块的数量,这种方式常用在读写二进制文件中;

每次一个字符的文件读取:

 int getc(FILE *stream); int fgetc(FILE *stream); int getchar(void);

getc函数和fgetc函数的作用是相同的,参数stream指向一个文件的文件流指针,返回从文中读取的一个字符,若读取失败,返回EOF;

以上即是本篇文章的全部内容,欢迎在下方留言板评论留言!

往期回顾



01


02


03


04