《Linux应用文件编程(二) — 标准IO》

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。

  

 

《Linux应用文件编程(二) — 标准IO》

上一篇:VMware12 打不开Centos6.8系统


下一篇:linux 性能优化之CPU性能(2)