/******************************************************************
*** 标准I/O库
*** 对于标准I/O库,它们的操作是围绕流(stream)进行的
*** 用标准I/O库打开或者创建一个文件时,我们就将一
*** 个流和一个文件相关联
******************************************************************/
对于ASCII字符集,一个字符用一个字节表示。对于国际字符集,一个字符可用多个字节表示。标准I/O文件流可用于单字节或多字节(“宽”)字符集。流的定向决定了所读、所写字符是单字节还是多字节。当一个流最初被创建时,它并没有定向。如若在未定向的流上使用一个多字节I/O函数,则将该流的定向设置为宽定向的。若在未定向的流上使用一个单字节I/O函数,则将该流的定向设置为字节定向的。
只有两个函数可以改变流的定向。freopen函数清除一个流的定向;fwide函数设置流的定向。
#include<wchar.h>
int fwide(FILE *fp,int mode);
若mode参数值为负,fwide将试图使指定的流是字节定向的。
若mode参数值为正,fwide将试图使指定的流是宽定向的。
若mode参数值为0,fwide将不试图设置流的定向,但返回标识该流定向的值
三种标准输入、输出、出错:
stdin
stdout
stderr
缓冲:
标准I/O提供了三种类型的缓冲
(1)全缓冲:在填满标准I/O缓冲区后才进行实际I/O操作。对于驻留在磁盘上的文件通常采用全缓冲。在一个流上执行第一次I/O操作时,相关标准I/O函数通常调用malloc函数获得需使用的缓冲区。
(2)行缓冲。当在输入和输出中遇到换行符时,标准I/O库执行I/O操作。当流涉及一个终端时,通常使用行缓冲。
对于行缓冲有两个限制:
第一、因为标准I/O库用来收集每一行的缓冲区的长度是固定的,所以只要填满了缓冲区,那么即使还没有写一个换行符,也进行I/O操作。
第二、任何时候只要通过标准I/O库要求从一个不带缓冲的流,或者一个行缓冲的流得到数据,那么就会造成冲洗所有行缓冲输出流。
(3) 不带缓冲。标准库不对字符进行缓冲存储。标准出错流通常是不带缓冲的。
void setbuf(FILE *restrict fp, char *restrict buf);
int setvbuf(FILE *restrict fp, char *restrict buf, int mode, size_t size);
setbuf函数打开或者关闭缓冲机制,参数buf是一个指定长度为BUFSIZ的缓冲区。buf设置为NULL ,则表示关闭缓冲区。
setvbuf函数可以精确的指定所需的缓冲类型。这是用mode参数实现的:
mode:
_IOFBF 全缓冲
_IOLBF 行缓冲
_IONBF 不带缓冲
如果指定一个不带缓冲区的流,则忽略buf和size参数。如果指定全缓冲或行缓冲,则buf和size可以选择的指定一个缓冲区和长度,如果该流是带缓冲的,而buf是NULL,则标准I/O库将自动的分配适当长度的缓冲区。适当长度指的是由常量BUFSIZ所指定的值。
打开流:
FILE *fopen(const char *restrict pathname,const char *restrict type);
FILE *freopen(const char *restrict pathname,const char *restrict type,FILE *restrict fp);
FILE *fdopen(int filedes,const char *type);
三个函数成功返回文件指针,失败返回NULL
(1)、fopen打开一个指定的文件
(2)、freopen在一个指定的流上打开一个指定的文件,如若该流已经打开,则先关闭该流。若该流已经定向,则freopen清除该定向。此函数一般用于将一个指定的文件打开为一个预定义的流:标准输入、标准输出或标准出错;
(3)、fdopen获取一个现有的文件描述符,并使一个标准的I/O流与该描述符相结合。此函数常用于由创建管道和网络通信通道函数返回的描述符。因为这些特殊类型的文件不能用标准I/O fopen打开,所以我们必须先调用设备专用的函数以获得一个文件描述符,然后用fdopen使一个标准I/O流与该描述符相关联。
type参数是对该I/O流的读、写方式
读和写流:
一旦打开了流,则可以在三种不同类型的非格式I/O中进行选择,对其进行读写:
1.每次一个字符的I/O。 一次读或写一个字符,如果流是带缓冲的,则标准I/O函数会处理所有缓冲。
2.每次一行的I/O。 如果想要一次读或者写一行数据,则适用fgets和fputs。每行都以一个换行符终止。当调用fgets时,应说明能处理的最大行长。
3.直接I/O。fread和fwrite函数支持这种类型的I/O。每次I/O操作读或写某种数量的对象,而每个对象具有指定的长度。这两个函数常用于从二进制文件中每次读或写一个结构。
一、每次一个字符的I/O:
1.输入函数:
int getc(FILE *fp);
int fgets(FILE *fp);
int getchar(void); //等价于getc(stdin)
这三个函数成功则返回下一个字符,到达文件尾或者出错返回EOF 为了 区分不同情况必须调用一下函数:
int ferror(FILE *fp);
int feof(FILE *fp);
成功返回非零,否则返回0
在大多数实现中,为每个流在FILE对象中维持了两个标志:
出错标志 和文件结束标志
void clearerr(FILE *fp);//清空错误标志和文件结束标志:
从流中读取数据之后,可以调用ungetc将字符再压送会流中
int ungetc(int c,FILE *fp); //成功返回c 否则返回EOF
2.输出函数:
int putc(int c,FILE *fp);
int fputc(int c,FILE *fp);
int putchar(int c);
三个函数成功返回c 失败返回EOF
二、每次一行的I/O
1.输入函数:
char *fgets(char *restrict buf,int n,FILE *restrict fp);
char *gets(char *buf); //从标准输入读。
两个函数成功返回buf,失败返回NULL
fgets 需要指明缓冲区buf的长度n,此函数一直读到换行符为止,读入的数据不能超多n-1个字符,否则读入的将是一个不完整的字符串。buf以NULL结尾。
2.输出函数:
int puts(const char *str);//将一个以null结尾的字符串写到标准输出,null不写出。
int fputs(const char *restrict str,FILE *fp);
两个函数成功返回非负值,出错返回EOF
三、二进制I/O
size_t fread(void *restrict ptr, size_t size, size_t nobj, FILE *restrict fp);
size_t fwrite(const void *restrict ptr, size_t size, size_t nobj, FILE *restrict fp);
两个函数返回成功读取或者写入的对象数。
ptr 为要读入或者写入的数据缓冲区, size为 每个对象的字节数, nobj为要读取或者写入的个数,fp为指定的流。
四、格式化I/O
1.格式化输出:
int printf(const char *restrict format, ...);
int fprintf(FIlE *restrict fp, const *restrict format, ...);
//两个函数 成功返回输出字符数,出错返回负值。
int sprintf(char *restrict buf,const char *restrict format, ...);
int snprintf(char *restrict buf, size_t n, const char *restrict format, ...);
//两个函数 成功返回存入buf中的字符数,若编码出错则返回负值。
2.格式化输入:
int scanf(const char *restrict format, ... );
int fscanf(FILE *restrict fp, const char *restrict format, ...):
int sscanf(const char *restrict buf, const char *restrict format, ...):
成功返回输入的项数,否则返回EOF
五、 定位流
有三种方式定位标准I/O流
1. ftell和fseek函数:
long ftell (FILE *fp);//成功返回当前文件位置,出错返回-1
int fseek (FILE *fp, long offset, int whence); //成功返回0,失败返回非零值
void rewind(FILE *fp);//将流设置到文件的起始位置
whence 的取值:
SEEK_SET---------表示从文件的起始位置开始
SEEK_CUR---------表示从文件的当前位置开始
SEEK_END---------表示从文件的结束位置开始
offset 值可正可负;
2. ftello 和 fseeko函数:
off_t ftello(FILE *fp);//成功返回当前文件位置,出错返回-1
int fseeko(FILE *fp, off_t offset, int whence);//成功返回0,失败返回非零值
和ftell与fseek函数相同;
3. fgetpos和fsetpos函数
int fgetpos(FILE *restrict fp, fpos_t *restrict pos);
int fsetpos(FILE *fp, const fpos_t pos);
两个函数成功返回0,失败返回非零值
fgetpos将文件位置指示器的当前值存入有pos指向的对象中。在以后调用fsetpos时,可以用此值将流重新定位到该位置。
六、其他
int fileno(FILE *fp); //返回与该流相关联的文件描述符
临时文件:
char *tmpnam(char *ptr);//返回唯一路径名的指针
FILE *tmpfile(void);//成功返回文件指针,出错返回NULL
tmpnam函数产生一个与现有文件名不同的一个有效路径名字符串。每次调用都产生一个不同的路径名。最多调用TMP_MAX次。
若ptr是NULL,则所产生的路径名存放在一个静态区中,指向该静态区的指针作为函数值返回,下一次调用tmpnam时,会重写该静态区(这意味着,如果我们调用此函数多次,而且想保存路径名,则我们应当保存该路径名的副本,而不是指针的副本)。若ptr不是NULL,则认为它指向长度至少时L_tmpnam个字符的数组(常量L_tmpnam定义在头文件stdio.h中),所产生的路径名存放在该数组中,ptr也作为函数值返回。
tmpfile创建一个临时二进制文件(类型wb+),在关闭文件或者程序结束时将自动删除这种文件。