1. 标准IO
与文件IO函数相类似,标准IO库中提供的是fopen、fclose、fread、fwrite等面向流对象的IO函数,这些函数在实现时本身就要调用linux的文件IO这些系统调用。
2. 标准IO的缓冲机制
由于IO设备的访问速度与CPU的速度相差好几个数量级,为了协调IO设备与CPU的速度的不匹配,对于块设备,内核使用了页高速缓存,即数据会先被拷贝到操作系统内核的页缓存区中,然后才会从操作系统内核的缓存区拷贝到应用程序的地址空间。
当应用程序尝试读取某块数据的时候,如果这块数据已经存放在页缓存中,那么这块数据就可以立即返回给应用程序,而不需要经过实际的物理读盘操作。当然,如果数据在应用程序读取之前并未被存放在页缓存中,那么就需要先将数据从磁盘读到页缓存中去。对于写操作来说,应用程序也会将数据先写到页缓存中去,数据是 否被立即写到磁盘上去取决于应用程序所采用的写操作机制:如果用户采用的是同步写机制,那么数据会立即被写回到磁 盘上,应用程序会一直等到数据被写完为止;如果用户采用的是延迟写机制,那么应用程序就完全不需要等到数据全部被 写回到磁盘,数据只要被写到页缓存中去 就可以了。在延迟写机制的情况下,操作系统会定期地将放在页缓存中的数据刷到磁盘上。与异步写机制不同的是,延迟写机制在数据完全写到磁盘上得时候不会通 知应用程序,而异步写机制在数据完全写到磁盘上得时候是会返回给应用程序的。
标准IO提供三种类型的缓冲机制:
全缓冲:
填满标准IO缓冲区后才进行实际的IO操作。对于在磁盘上的文件通常由标准IO库实施全缓冲的。在一个流上执行第一次I/O操作时,相关标准I/O函数通常调用malloc获得需使用的缓存区。
行缓冲:
当在输入和输出中遇到换行符时,标准IO库执行IO操作。通常涉及到终端(例如标准输入和标准输出)使用的是行缓冲。
对于行缓冲有两个限制:
第一,因为标准IO库用来收集每一行的缓冲区的长度是固定的,所以只要填满了缓冲区,那么即使还没有写一个换行符,也进行IO操作。
第二,任何时候只要通过标准IO库要求从(a)一个不带缓存的流,或者(b)一个行缓存的流(它要求从内核得到数据)得到输入数据,那么就会造成冲洗所有行缓冲输出流(因为后面读取的数据可能就是前面输出的数据)。其实第二种情况我们会经常遇到,当我们先调用printf输出一串不带换行符的字符时,执行完这条printf语句并不会立刻在屏幕中显示我们输出的数据,当我们接下来调用scanf从标准输入读取数据时,我们才看到前面输出的数据。
不带缓冲:
标准IO库不对字符进行存储。例如,如果用标准IO函数fputs写15个字符到不带缓冲的流中,则该函数很可能直接调用write系统调用将这些字符立即写到相关的文件中。标准出错流stderr是不带缓冲的,这样为了让出错的信息可以尽快的显示出来。
3. 标准IO函数
3.1 fopen函数
#include <stdio.h> FILE *fopen(const char *path, const char *mode);//mode为操作权限 FILE *fdopen(int fd, const char *mode); FILE *freopen(const char *path, const char *mode, FILE *stream); 返回值: 成功返回一个FILE文件流指针,失败返回NULL,并且设置errno全局变量。 参数: mode: r:只读方式打开文件,返回的文件流指针位于文件开始 r+ :读写方式打开文件,返回的文件流指针位于文件开始 w:如果文件存在,清除文件写,如果文件不存在,创建文件写 w+:读写方式打开文件,文件不存在创建文件,存在则清空文件 a:追加写方式打开文件,如果不存在则创建文件,流指针位于文件尾 a+:读和追加写方式打开,如果文件不存在则创建文件,
3.2 fread函数
#include <stdio.h> size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); 返回值: 成功返回读取的字节数,到达文件尾返回0,失败返回一个短数。 参数: Ptr:读取的数据存储的位置 Size:读取的每个单元的大小 Nmemb:读取的单元数量 Stream:从哪个文件流读取数据
fread不能区分到达文件尾和错误,因此必须使用feof和ferror函数确定是到达文件尾,还是发生错误。
3.3 fwrite函数
#include <stdio.h> size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream); 返回值: 成功返回写入的字节数,到达文件尾返回0,失败返回一个短数。 参数: Ptr:写入的数据的位置 Size:每次写入的单元的大小 Nmemb:写入的单元数 Stream:写入到哪个文件流
3.4 fclose函数
#include <stdio.h> int fclose(FILE *fp); 返回值: 成功返回0,刷新缓存,失败返回EOF,并且设置errno。
3.5 fseek函数、ftell函数、rewind函数
#include <stdio.h> int fseek(FILE *stream, long offset, int whence); long ftell(FILE *stream); void rewind(FILE *stream); rewind()函数无返回值,fseek成功返回0,ftell成功返回当前偏移量,失败返回-1,并且设置errno。