日期:2014-05-16  浏览次数:20686 次

Linux/UNIX之标准IO库

标准IO库

当打开一个流时,标准I/O函数fopen返回一个指向FILE对象的指针。该对象通常是一个结构,它包含了标准I/O库为管理该流所需的所有信息,包括:用于实际I/O的文件描述符、指向用于该缓冲区的指针、缓冲区的长度、当前在缓冲区的字符数以及出错标志等。为引用一个流,需将FILE指针作为参数传递给每个标准I/O函数。

对于标准输入、标准输出和标准出错,他们的文件描述符对应STFIN_FILENO、STDOUT_FILENO和STDERR_FILENO。这三个标准I/O流通过预定义stdin、stdout和stderr加以引用。这三个文件指针以及标准I/O函数都定义在头文件<stdio.h>中。

缓冲

标准I/O库提供缓冲的目的是尽可能减少使用read和write调用次数。提供了三种类型的缓冲:

1)      全缓冲:需在填满标准I/O缓冲区后才进行实际I/O操作。

2)      行缓冲:当在输入和输出中遇到换行符时,标准I/O库执行I/O操作。

3)      不带缓冲:标准I/O库不对字符进行缓冲存储。

一般而言,标准出错是不带缓冲的,打开终端设备的流是行缓冲的,其他所有流则是全缓冲的。当流是全缓冲,但该缓冲区是局部填写时,可用fflush函数冲洗。

可调用下面的函数更改缓冲区类型:

#include <stdio.h>

void setbuf(FILE *stream, char *buf);

int setvbuf(FILE *stream, char *buf, intmode, size_t size);

任何时候,我们都可以强制冲洗一个流:

#include <stdio.h>

int fflush(FILE *stream);

此函数将使该流所有未写的数据都被传送至内核。作为一个特例,如若fp是NULL,则此函数将导致所有输出流被冲洗。

打开流

#include <stdio.h>

FILE *fopen(const char *path, const char*mode);

FILE *fdopen(int fd, const char *mode);

FILE *freopen(const char *path, const char*mode, FILE *stream);

这三个函数的区别是:

1)      fopen打开一个指定的文件。

2)      fropen在一个指定的留上打开一个指定的文件,如若该流已经打开,则先关闭该流。如若该流已经定向,则fopen清除该定向。此函数一般用于将一直指定的文件打开为一个预定义的流:标准输入、标准输出或标准错误。

3)      fdopen获取一个现有的文件描述符,并使一个标准的I/O流与该描述符相结合。此函数常用于由创建管道和网络通信函数返回的描述符。因为这些特殊类型的文件不能用标准I/Ofopen函数打开,所有我们必须先调用设备专用函数以获得一个文件描述符,然后用fopen使一个标准I/O与该描述符相关联。

其中的mode参数可以用是以下15种不同的值:
r或rb:                    为读打开

w或wb:                 把文件截短至0长,或为写而创建

a或ab:                      添加;为在文件写打开,或为写打开

r+或r+b或rb+:       为读和写打开

w+或w+b或wb+:  把文件截短至0,或为读和写打开

a+或a+b或ab+:     为在文件尾端读和写而打开或创建

 

#include <stdio.h>

int fclose(FILE *fp);

在文件被关闭之前,冲洗缓冲区中的输出数据。如果标准I/O库已经为该流自动分配了一个缓冲区,则释放缓冲区。

读和写流

一旦打开了流,则可在三种不同类型的非格式化I/O中进行选择,对其读、写操作:

1)      每次一个字符是I/O。一次读或写一个字符,如果流是带缓冲区的,则标准I/O函数会处理所有缓冲。

2)      每次一行的I/O。如果想要一次读或写一行,则使用fgets和fputs。每行都以一个换行符终止。当调用fgets时,应说明能处理的最大行长。

3)      直接I/O。fread和fwrite函数支持这种类型的I/O。

每次一个字符I/O

输入函数:

#include <stdio.h>

int getc(FILE *stream);

int fgetc(FILE *stream);

int getchar(void);

getchar()等价于getc(stdin)。getc和fgetc区别在于getc可被实现为宏,而fgetc则不能实现为宏。

不管是出错还是到达文件尾端,这三个函数都返回同样的值。为了区分出错和到达文件尾端,必须调用ferror和feof函数。

#include <stdio.h>

int feof(FILE *stream);

int ferror(FILE *stream);

这两个函数的返回值:若条件为真则返回非0值,否则返回0。

每个流在FILE对象中维持了两个标志:出错标志和文件结束标志

调用clearerr则清除这两个标志。

void clearerr(FILE *stream);

从流读取数据后,可以调用ungetc将字符再压入回流中。

int ungetc(int c, FILE *stream);

压入回流中的字符以后又可以从流中读出,但读出的字符顺序与压送回的顺序相反。

对于输出函数:

#include <stdio.h>

int putc(int c, FILE *stream);

int fputc(int c, FILE *stream);

int putchar(int c);

与输入函数一样putchar(c)等效于putc(c, stdout)。putc可实现为宏。

每次一行I/O

#include <stdio.h>

char *fgets(char *s, int size, FILE*stream);

char *gets(char *s);

fgets从指定的流读,必须指定缓冲区长度size。此函数一直读到下一个换行符为止,但是不超过n-1个字符,读入的字符被送入缓冲区。该缓冲区以null字符结尾。如若改行(包括最后一个换行符)的字符数超过n-1,则fgets只返回一个不完整的行,但是缓冲区总是以null字符结尾。对fgets的下一次调用会继续读改行。

  &nbs