4.1 流和FILE对象

        对于标准I/O库,它们的操作则是围绕流 (stream)进行的。当用标准I/O库打开或创建一个文件时,我们已使一个流与一个文件相结合。

        当打开一个流时,标准I/O函数fopen返回一个指向FILE对象的指针。该对象通常是一个结 构,它包含了I/O库为管理该流所需要的所有信息:用于实际 I/O的文件描述符,指向流缓存的指针,缓存的长度,当前在缓存中的字符数,出错标志等等。

4.2 标准输入、标准输出和标准出错

        对一个进程预定义了三个流,它们自动地可为进程使用:标准输入、标准输出和标准出错。 用文件描述符STDIN_FILENO , STDOUT_FILENO和STDERR_FILENO分别表示它们。

4.3 缓存

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

(1)全缓存。在这种情况下,当填满标准I/O缓存后才进行实际I/O操作。对于驻在磁盘上的文件通常是由标准I/O库实施全缓存的。

(2)行缓存。在这种情况下,当在输入和输出中遇到新行符时,标准I/O库执行I/O操作。这允许我们一次输出一个字符(用标准 I/O fputc函数),但只有在写了一行之后才进行实际 I/O操 作。当流涉及一个终端时(例如标准输入和标准输出),典型地使用行缓存。

(3)不带缓存。标准I/O库不对字符进行缓存。如果用标准I/O函数写若干字符到不带缓存的流中,则相当于用write系统调用函数将这些字符写至相关联的打开文件上。标准出错流stderr通常是不带缓存的,这就使得出错信息可以尽快显示出来,而不管它们是否含有一个新行字符。

可调用下列两个函数中的一个 更改缓存类型:

#include <stdio.h>

//返回:若成功则为0,若出错则为非0
void setbuf(FILE *fp, char * buf ) ;
int setvbuf(FILE *fp, char *buf, int mode, size_t size) ;

        可以使用setbuf函数打开或关闭缓存机制。为了带缓存进行I/O,参数buf 必须指向一个长度为BUFSIZ的缓存(该常数定义在<stdio.h>中)。通常在此之后该流就是全缓存的,但是如果该流与一个终端设备相关,那么某些系统也可将其设置为行缓存的。为了关闭缓存,将buf设置为NULL。

        使用setvbuf,我们可以精确地说明所需的缓存类型。这是依靠mode参数实现的:

  • _IOFBF 全缓存
  • _IOLBF 行缓存
  • _IONBF 不带缓存

        任何时候,我们都可强制刷新一个流。

# include <stdio.h>

//返回:若成功则为0,若出错则为E O F
int fflush(FILE * fp) ;

        此函数使该流所有未写的数据都被传递至内核。作为一种特殊情形,如若fp是NULL,则此函 数刷新所有输出流。

4.4 打开流

        下列三个函数可用于打开一个标准I/O流。

#include <stdio.h>

//三个函数的返回:若成功则为文件指针,若出错则为NULL
FILE *fopen(const char * pathname, const char * type) ;
FILE *freopen(const char * pathname, const char * type, FILE * fp) ;
FILE *fdopen(int filedes, const char * type) ;

这三个函数的区别是:

(1)fopen打开路径名由pathname 指示的一个文件。

(2)freopen在一个特定的流上(由fp指示)打开一个指定的文件(其路径名由pathname 指示), 如若该流已经打开,则先关闭该流。此函数一般用于将一个指定的文件打开为一个预定义的流: 标准输入、标准输出或标准出错。

(3)fdopen取一个现存的文件描述符(我们可能从open , dup , dup2 , fcntl或pipe函数得到此文 件描述符),并使一个标准的I/O流与该描述符相结合。此函数常用于由创建管道和网络通信通 道函数获得的插述符。因为这些特殊类型的文件不能用标准 I/O fopen函数打开,首先必须先调用设备专用函数以获得一个文件描述符,然后用 fdopen使一个标准I/O流与该描述符相结合。

        type参数指定对该I/O流的读、写方式。

使用字符b作为type的一部分,使得标准I/O系统可以区分文本文件和二进制文件。

        调用fclose关闭一个打开的流。

#include <stdio.h>

int fclose(FILE * fp) 

4.5 读和写流

4.5.1 输入函数

        以下三个函数可用于一次读一个字符。

#include <stdio.h>

//三个函数的返回:若成功则为下一个字符,若已处文件尾端或出错则为EOF
int getc(FILE * fp) ;
int fgetc(FILE * fp) ;
int getchar(void);

4.5.2 输出函数

        对应于上面所述的每个输入函数都有一个输出函数。

#include <stdio.h>

//三个函数返回:若成功则为 C,若出错则为EOF
int putc(int c, FILE * fp ) ;
int fputc(int c, FILE * fp);
int putchar(int c) ;

4.6 每次一行I/O

        下面两个函数提供每次输入一行的功能。

#include <stdio.h>

//两个函数返回:若成功则为buf,若已处文件尾端或出错则为NULL
char *fgets(char * buf, int n,FILE * fp) ;
char *gets(char * buf) ;

        fputs和puts提供每次输出一行的功能。

#include <stdio.h>

//两个函数返回:若成功则为非负值,若出错则为EOF
int fputs(const char * str, FILE * fp) ;
int puts(const char * str) ;

4.7 二进制I/O

        下列两个函数执行二进制I/O操作。

#include <stdio.h>

//两个函数的返回:读或写的对象数
size_t fread(void * ptr, size_t size, size_t nobj, FILE * fp) ;
size_t fwrite(const void * ptr, size_t size, size_t nobj, FILE * fp) ;

4.8 定位流

        有两种方法定位标准I / O流。

(1)ftell和fseek。它们都假定文件的位置可以存放在 一个长整型中。

(2)fgetpos和fsetpos。它们引进了一个新的抽象数据类 型fpos_t,它记录文件的位置。在非UNIX系统中,这种数据类型可以定义为记录一个文件的位置所需的长度。

#include <stdio.h>

//返回:若成功则为当前文件位置指示,若出错则为-1
long ftell(FILE * fp) ;

//返回:若成功则为0,若出错则为非0
int fseek(FILE * fp,long offset,int whence) ;

void rewind(FILE *f p)
#include <stdio.h>

//两个函数返回:若成功则为 0,若出错则为非0
int fgetpos(FILE * fp, fpos_t * pos) ;
int fsetpos(FILE * fp, const fpos_t * pos) ;

4.9 格式化I/O

4.9.1 格式化输出

        执行格式化输出处理的是三个printf函数。

#include <stdio.h>

//两个函数返回:若成功则为输出字符数,若输出出错则为负值
int printf(const char * format, ...);
int fprintf(FILE * fp, const char * format, ...);

//返回:存入数组的字符数
int sprintf(char * buf, const char * format, ...);

printf将格式化数据写到标准输出,fprintf写至指定的流,sprint f将格式化的字符送入数组buf中。 sprintf在该数组的尾端自动加一个null字节,但该字节不包括在返回值中。

        下列三种printf族的变体类似于上面的三种,但是可变参数表( . . . )代换成了arg。

# include <stdarg.h>
# include <stdio.h>

//两个函数返回:若成功则为输出字符数,若输出出错则为负值
int vprintf(const char * format, va_list arg) ;
int vfprintf(FILE * fp, const char * format, va_list arg) ;

//返回:存入数组的字符数
int vsprintf(char * buf, const char * format, va_list arg) ;

4.9.2 格式化输入

        执行格式化输入处理的是三个scanf函数。

# include <stdio.h>

//三个函数返回:指定的输入项数,若输入出错,或在任意变换前已至文件尾端则为EOF
int scanf(const char * format, ...);
int fscanf(FILE * fp, const char * format, ...);
int sscanf(const char * buf, const char * format, ...);
05-05 05:25