对于标准I/O库,它们的操作是围绕流(stream)进行的,当用标准I/O库打开或者创建一个文件时,我们已使一个流与一个文件相关联。
对于ASCII字符集,一个字符用一个字节表示。对于国际字符集,一个字符可用多个字节表示。标准I/O文件流可用于单字节或多字节字符集。freopen函数清除一个流的定向,fwide函数可用于设置流的定向。
#include
// A positive return value means wide-character oriented.
// A negative return value means byte oriented.
// A return value of zero means undecided.
int fwide(FILE* stream, int mode);
根据mode参数的不同,fwide函数执行不同的功能:
[1] 如若mode参数值为负,fwide将试图使指定的流是字节定向的。
[2] 如若mode参数值为正,fwide将试图使指定的流是宽定向的。
[3] 如若mode参数值为0,fwide将不试图设置流的定向,但返回标识该流定向的值。
对一个进程预定义了三个流:标准输入、标准输出和标准错误,这三个标准I/O流通过预定义文件指针stdin、stdout和stderr加以引用,被定义在
标准I/O库提供缓冲是为了尽可能减少read和write调用的次数。它也对每个 标准I/O流自动地进行缓冲管理。
标准I/O提供了以下3种类型的缓冲:
[1] 全缓冲:在填满标准I/O缓冲区后才进行实际I/O操作。
[2] 行缓冲:当输入和输出中遇到换行符时,标准I/O库执行I/O操作,当流涉及一个终端时,往往使用行缓冲。
[3] 不带缓冲:标准I/O库部队字符进行缓冲存储。
ISO/C要求下列缓冲特征:
[1] 当且仅当标准输入和标准输出并不指向交互式设备时,他们才是全缓冲的。
[2] 标准错误决不是全缓冲的。
[3] 标准错误时不带缓冲的。
[4] 若是指向终端设备的流,则是行缓冲的,否则是全缓冲的。
对于任何一个给定的流,可以调用下面两个函数更改缓冲类型。
#include
void setbuf(FILE* stream, char* buf);
int setvbuff(FILE* stream, char* buf, int mode, size_t size);
mode参数:
_IOFBF 全缓冲
_IOLBF 行缓冲
_IONBF 不带缓冲
函数 | mode | buf | 缓冲区及长度 | 缓冲类型 |
---|---|---|---|---|
setbuf | 非空 | 长度为BUFSIZ的用户缓冲区buf | 全缓冲或行缓冲 | |
setbuf | NULL | (无缓冲区) | 不带缓冲 | |
setvbuf | _IOFBF | 非空 | 长度为size的用户缓冲区buf | 全缓冲 |
setvbuf | _IOFBF | NULL | 合适长度的系统缓冲区buf | 全缓冲 |
setvbuf | _IOLBF | 非空 | 长度为size的用户缓冲区buf | 行缓冲 |
setvbuf | _IOLBF | NULL | 合适长度的系统缓冲区buf | 行缓冲 |
setvbuf | _IONBF | (忽略) | (无缓冲区) | 不带缓冲 |
任何时候,我们都可以强制冲洗一个流。
#include
int fflush(FILE* stream);
此函数使该流所有未写的数据都被传送至内核,若stream是NULL,则此函数将导致所有输出流被冲洗。
下列3个函数打开一个标准I/O流。
#include
// return a file pointer or NULL if an error occurred.
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函数打开路径名为pathname的一个指定的文件。
[2] freopen函数在一个指定的流上打开一个指定的文件,若流已经打开,则先关闭,若流已经定向,则用freopen清楚定向。一般用于将一个指定的文件打开为一个预定义的流:标准输入、标准输出或标准错误。
[3] fdopen函数取一个已有的文件描述符,并使一个标准的I/O流与该描述符相结合。此函数通常用于创建管道和网络通信管道函数返回的描述符。
type | 说明 | open(2)标志 |
---|---|---|
r或rb | 为读而打开 | O_RDONLY |
w或wb | 把文件截断至0或为写而创建 | O_WRONLY | O_CREAT | O_TRUNC |
a或ab | 追加或为写而打开 | O_WRONLY | O_CREAT | O_APPEND |
r+或r+b或rb+ | 为读和写而打开 | O_RDWR |
w+或w+b或wb+ | 把文件截断至0或为写而打开 | O_RDWR | O_CREAT | O_TRUNC |
a+或a+b或ab+ | 为在文件尾读和写而打开或创建 | O_RDWR | O_CREAT | O_APPEND |
对于fdopen函数,type参数的意义有些不同1
当以读和写的方式打开一个文件时具有下列限制
[1] 如果中间没有fflush、fseek、fsetpos或rewind,则在输出后不能直接跟随输入。
[2] 如果中间没有fseek、fsetpos、或rewind,或者一个输入操作没有到达文件尾端,则在输入操作之后不能直接跟随输出。
调用fclose关闭一个打开的流。
#include
// return 0 or EOF if an error occurred.
inf fclose(FILE* fp);
一旦打开了流,则可以在3中不同类型的非格式化I/O中进行选择,对其进行读、写操作。
[1] 每次一个字符的I/O,如果流是带缓冲的,则标准I/O函数处理所有缓冲。
[2] 每次一行的I/O。
[3] 直接I/O。
#include
int get(FILE* stream);
int fgetc(FILE* stream);
int getchar(void);
#include
int putc(int c, FILE* stream);
int fputc(int c, FILE* stream);
int putchar(int c);
#include
int ungetc(int c, FILE* stream);
函数getchar等同于getc(stdin),最好使用fgetc函数,更安全。
函数putchar©等同于putc(c, stdout),最好使用fputc函数。
从流中读取数据后,可以调用ungetc将字符再压送回流中。
#include
char* gets(char* s);
char* fgets(char* s, int size, FILE* stream);
#include
int puts(const char* s);
int fputs(const char* s, FILE* stream);
#include
size_t fread(void* ptr, size_t size, size_t nmemb, FILE* stream);
size_t fwrite(const void* ptr, size_t size, size_t nmemb, FILE* stream);
// usage
float data[10];
if (fwrite(&data[2], sizeof(float), 4, fp) != 4)
// error handler.
struct
{
short count;
long total;
char name[255];
} item;
if (fwrite(&item, sizeof(item), 1, fp) != 1)
// error handler.
#include
int fseek(FILE* stream, long offset, int whence);
long ftell(FILE* stream);
void rewind(FILE* stream);
int fseeko(FILE* stream, off_t offset, int whence);
off_t ftello(FILE* stream);
int fgetpos(FILE* stream, fpos_t* pos);
int fsetpos(FILE* stream, fpos_t* pos);
#include
int printf(const char* format, ...);
int fprintf(FILE* stream, const char* format, ...);
int dprintf(int fd, const char* format, ...);
int sprintf(char* str, const char* format, ...);
int snprintf(char* str, size_t size, const char* format, ...);
#include
int vprintf(const char* format, va_list ap);
int vfprintf(FILE* stream, const char* format, va_list ap);
int vdprintf(int fd, const char* format, va_list ap);
int vsprintf(char* str, const char* format, va_list ap);
int vsnprintf(char* str, size_t size, const char* format, va_list ap);
具体格式化参数详见格式化字符串参数介绍.
#include
int scanf(const char* format, ...);
int fscanf(FILE* stream, const char* format, ...);
int sscanf(const char* str, const char* format, ...);
#include
int vscanf(cosnt char* format, va_list ap);
int vsscanf(const char* str, const char* format, va_list ap);
int vfscanf(FILE* stream, const char* format, va_list ap);
#include
char* tmpnam(char* s);
FILE* tmpfile(void);
由于该描述符已被打开,所以fdopen函数为写而打开并不截断该文件。另外,标准I/O追加写方式也不能用于创建该文件。 ↩︎