本文章说明标准I/O库
1.流和FILE对象
对于文件IO都是针对于文件描述符的,但是对于标准I/O,则是针对于流进行的
当用标准I/O库打开一个文件的时候,我们已使一个流和一个文件相关联
对于ASCII字符集,一个字符用一个字节表示,对于国际字符,一个字符可用多个字节表示
标准I/O文件流可用于单字节或多字节字符集
流的定向决定了所读、写的文件是单字节还是多字节的,当一个流被创建的时候,它没有被定向
如果在没有定向的流中使用多字节的I/O函数,则将该流的定向设置为宽定向的
如果在没有定向的流中使用单字节的I/O函数,则将该流的定向设置为字节定向
fwide函数可以设置流的定向
#include <stdio.h>
#include <fchar.h>
int fwide(FILE *fp, int mode);
//若流是宽定向的返回正值,若流是字节定向的返回负值,若流是未定向的返回0
若mode是正值,则函数试图设置流为宽定向的
若mode是负值,则函数试图设置流为字节定向的
若mode是0,则函数不设置流的定向,但是将返回标识该流定向的值
注意fwide函数不设置已经定向的流
2.标准输入,标准输出和标准错误输出
在<stdio.h>中定义了这三个流stdin, stdout, stderr
这三个流可以自动地被进程使用
3.缓冲
标准I/O提供缓冲是为了尽量减少read和write函数的调用
标准I/O提供了三种类型的I/O
(1)全缓冲
当缓冲区全部写满的时候在进行写入操作。
(2)行缓冲
当遇到换行符的时候进行写入操作,或者遇到换行符之前,缓冲区填满也进行写入
(3)不缓冲
ISO C要求下列缓冲特性:
当且仅当标准输入输出不涉及交互式设备的时候,它们才是全缓冲的
标准出错决不是全缓冲的
很多系统默认下列类型的缓冲特性:
标准出错不带缓冲
如若是涉及终端设备的其他流的时候,则它们是行缓冲的,否则是全缓冲的
可以调用下面两个函数更改缓冲类型:
#include <stdio.h>
void setbuf(FILE *restrict fp, char *restrict buf);
int setvbuf(FILE *restrict fp, char *restrict buf, int mode, size_t size);
//成功返回0,出错返回非零值
setbuf函数中,若buf非空,buf长度为BUFSIZ,则缓冲类型是全缓冲或者行缓冲,当buf为NULL的时候不缓冲
setvbuf函数中,不同的mode有不同的处理方式
_IOFBF 全缓冲,buf如下
当buf非空,缓冲区为长度为size的用户buf
当buf为BULL的时候,缓冲区为合适长度的系统缓冲区
_IOLBF 行缓冲,buf同理
_IONBF 不缓冲,buf和size忽略
强制冲洗一个流,将未写入的数据都传送给内核
#include <stdio.h>
int ffush(FILE *fp);
//成功返回0,出错返回EOF
4.打开流
打开一个标准I/O流
#include <stdio.h>
FILE *fopen(const char *restrict pathname, const char *restrict type);
//打开一个指定的文件
FILE *freopen(const char *restrict pathname, const char *restrict type, FILR *restrict fp);
//在一个指定的流上打开一个指定的文件,如若该流已经打开,则先关闭该流,若该流已经定向,则清除
FILE *fdopen(int filedesm const char *type);
//将一个现有的文件描述符与一个标准I/O流结合起来
//以上函数若成功返回文件指针,失败返回NULL
type指定对该I/O流的读写方式
r或rb 为读而打开
w或wb 把文件截短至0长,或为写而创建
a或ab 追加,或为写而创建
r+或r+b或rb+ 为读和写而打开
w+或w+b或wb+ 把文件截短至0长,或为读写而打开
a+或a+b或ab+ 在文件尾读和写而打开或创建
b作为type的一部分为了区分文本文件和二进制文件,但是UNIX系统并不区分这两种类型的文件,在UNIX下b是无用的
fdopen在为写而打开的时候并不截短文件
当以读和写类型打开一个文件的时候,有以下限制:
如果中间没有fflush、fseek、fsetpos和rewind的时候,则在输出后面不能直接跟随输入
如果中间没有fseek、fsetpos或rewind,或者一个输入操作没有达到文件尾端,在输入操作之后不能跟随输出
调用fclose关闭一个打开的流
#include <stdio.h>
int fclose(FILE *fp);
//成功返回0,出错返回EOF
5.读和写流
以下三个函数用于一次读一个字符
#include <stdio.h>
int getc(FILE *fp);
int fgetc(FILE *fp);
int getchar(void);//等价与getc(stdin);
//成功返回下一个字符,达到文件尾或出错返回EOF
为了区分是否达到文件尾还是出错,有以下函数
#include <stdio.h>
int ferror(FILE *fp);
int feof(FILE *fp);
//若条件为真,返回非零值,否则返回0
void clearerr(FILE *fp);//清除这两个标志
可以调用下面的函数将已经读出来的字符压送会流中
#include <stdio.h>
int ungetc(int c, FILE *fp);
//成功返回c,失败返回EOF
使用这个函数时,字符送到了流的缓冲区中
输出函数
#include <stdio.h>
int putc(int c, FILE *fp);
int fputc(int c, FILE *fp);
int putchar(int c);
//成功返回buf,出错返回EOF
6.每次一行I/O
下面函数提供每次输入一行的函数
#include <stdio.h>
char *fgets(char *restrict buf, int n, FILE *restrict fp);
char *gets(char *buf);
//成功返回buf,到达文件尾或失败返回EOF
//gets函数不安全,不建议使用
每次输出一行:
#include <stdio.h>
int fputs(const char *restrict str, FILE *restrict fp);
int puts(const char *str);
//成功返回非负值,出错返回EOF
7.二进制I/O
执行二进制I/O的操作
#include <stdio.h>
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);
//返回读和写的对象数
//nobj为读写的对象数
8.格式化I/O
格式化输出函数
#include <stdio.h>
int printf(const char *restrict format, ...);
int fprintf(FILE *restrict fp, const char *restrict format, ...);
//成功返回输出的字符数,失败返回负值
int sprintf(char *restrict buf, const char *restrict format, ...);
int snprintf(char *restrict buf, size_t n, const char *restrict format, ...);
//成功返回存入数组的字符数,失败返回负值
printf格式化写到标准输出
fprintf格式化写到指定的流
sprintf和snprintf格式化写到数组buf中
格式化输入函数
#include <stdio.h>
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
9.实现细节
获取一个流所对应的文件描述符
#include <stdio.h>
int fileno(FILE *fp);
//返回与流相关的文件描述符
10.临时文件
创建临时文件
#include <stdio.h>
char tmpnam(char *ptr);
//返回唯一路径名的指针
FILE *tmpfile(void);
//成功返回文件指针,失败返回NULL
每次调用tmpnam返回一个与文件名不同的有效路径名字符串
tmpfile产生一个临时的二进制文件(wb+)。在关闭该文件或程序结束的时候将自动删除这个文件。
1.流和FILE对象
对于文件IO都是针对于文件描述符的,但是对于标准I/O,则是针对于流进行的
当用标准I/O库打开一个文件的时候,我们已使一个流和一个文件相关联
对于ASCII字符集,一个字符用一个字节表示,对于国际字符,一个字符可用多个字节表示
标准I/O文件流可用于单字节或多字节字符集
流的定向决定了所读、写的文件是单字节还是多字节的,当一个流被创建的时候,它没有被定向
如果在没有定向的流中使用多字节的I/O函数,则将该流的定向设置为宽定向的
如果在没有定向的流中使用单字节的I/O函数,则将该流的定向设置为字节定向
fwide函数可以设置流的定向
#include <stdio.h>
#include <fchar.h>
int fwide(FILE *fp, int mode);
//若流是宽定向的返回正值,若流是字节定向的返回负值,若流是未定向的返回0
若mode是正值,则函数试图设置流为宽定向的
若mode是负值,则函数试图设置流为字节定向的
若mode是0,则函数不设置流的定向,但是将返回标识该流定向的值
注意fwide函数不设置已经定向的流
2.标准输入,标准输出和标准错误输出
在<stdio.h>中定义了这三个流stdin, stdout, stderr
这三个流可以自动地被进程使用
3.缓冲
标准I/O提供缓冲是为了尽量减少read和write函数的调用
标准I/O提供了三种类型的I/O
(1)全缓冲
当缓冲区全部写满的时候在进行写入操作。
(2)行缓冲
当遇到换行符的时候进行写入操作,或者遇到换行符之前,缓冲区填满也进行写入
(3)不缓冲
ISO C要求下列缓冲特性:
当且仅当标准输入输出不涉及交互式设备的时候,它们才是全缓冲的
标准出错决不是全缓冲的
很多系统默认下列类型的缓冲特性:
标准出错不带缓冲
如若是涉及终端设备的其他流的时候,则它们是行缓冲的,否则是全缓冲的
可以调用下面两个函数更改缓冲类型:
#include <stdio.h>
void setbuf(FILE *restrict fp, char *restrict buf);
int setvbuf(FILE *restrict fp, char *restrict buf, int mode, size_t size);
//成功返回0,出错返回非零值
setbuf函数中,若buf非空,buf长度为BUFSIZ,则缓冲类型是全缓冲或者行缓冲,当buf为NULL的时候不缓冲
setvbuf函数中,不同的mode有不同的处理方式
_IOFBF 全缓冲,buf如下
当buf非空,缓冲区为长度为size的用户buf
当buf为BULL的时候,缓冲区为合适长度的系统缓冲区
_IOLBF 行缓冲,buf同理
_IONBF 不缓冲,buf和size忽略
强制冲洗一个流,将未写入的数据都传送给内核
#include <stdio.h>
int ffush(FILE *fp);
//成功返回0,出错返回EOF
4.打开流
打开一个标准I/O流
#include <stdio.h>
FILE *fopen(const char *restrict pathname, const char *restrict type);
//打开一个指定的文件
FILE *freopen(const char *restrict pathname, const char *restrict type, FILR *restrict fp);
//在一个指定的流上打开一个指定的文件,如若该流已经打开,则先关闭该流,若该流已经定向,则清除
FILE *fdopen(int filedesm const char *type);
//将一个现有的文件描述符与一个标准I/O流结合起来
//以上函数若成功返回文件指针,失败返回NULL
type指定对该I/O流的读写方式
r或rb 为读而打开
w或wb 把文件截短至0长,或为写而创建
a或ab 追加,或为写而创建
r+或r+b或rb+ 为读和写而打开
w+或w+b或wb+ 把文件截短至0长,或为读写而打开
a+或a+b或ab+ 在文件尾读和写而打开或创建
b作为type的一部分为了区分文本文件和二进制文件,但是UNIX系统并不区分这两种类型的文件,在UNIX下b是无用的
fdopen在为写而打开的时候并不截短文件
当以读和写类型打开一个文件的时候,有以下限制:
如果中间没有fflush、fseek、fsetpos和rewind的时候,则在输出后面不能直接跟随输入
如果中间没有fseek、fsetpos或rewind,或者一个输入操作没有达到文件尾端,在输入操作之后不能跟随输出
调用fclose关闭一个打开的流
#include <stdio.h>
int fclose(FILE *fp);
//成功返回0,出错返回EOF
5.读和写流
以下三个函数用于一次读一个字符
#include <stdio.h>
int getc(FILE *fp);
int fgetc(FILE *fp);
int getchar(void);//等价与getc(stdin);
//成功返回下一个字符,达到文件尾或出错返回EOF
为了区分是否达到文件尾还是出错,有以下函数
#include <stdio.h>
int ferror(FILE *fp);
int feof(FILE *fp);
//若条件为真,返回非零值,否则返回0
void clearerr(FILE *fp);//清除这两个标志
可以调用下面的函数将已经读出来的字符压送会流中
#include <stdio.h>
int ungetc(int c, FILE *fp);
//成功返回c,失败返回EOF
使用这个函数时,字符送到了流的缓冲区中
输出函数
#include <stdio.h>
int putc(int c, FILE *fp);
int fputc(int c, FILE *fp);
int putchar(int c);
//成功返回buf,出错返回EOF
6.每次一行I/O
下面函数提供每次输入一行的函数
#include <stdio.h>
char *fgets(char *restrict buf, int n, FILE *restrict fp);
char *gets(char *buf);
//成功返回buf,到达文件尾或失败返回EOF
//gets函数不安全,不建议使用
每次输出一行:
#include <stdio.h>
int fputs(const char *restrict str, FILE *restrict fp);
int puts(const char *str);
//成功返回非负值,出错返回EOF
7.二进制I/O
执行二进制I/O的操作
#include <stdio.h>
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);
//返回读和写的对象数
//nobj为读写的对象数
8.格式化I/O
格式化输出函数
#include <stdio.h>
int printf(const char *restrict format, ...);
int fprintf(FILE *restrict fp, const char *restrict format, ...);
//成功返回输出的字符数,失败返回负值
int sprintf(char *restrict buf, const char *restrict format, ...);
int snprintf(char *restrict buf, size_t n, const char *restrict format, ...);
//成功返回存入数组的字符数,失败返回负值
printf格式化写到标准输出
fprintf格式化写到指定的流
sprintf和snprintf格式化写到数组buf中
格式化输入函数
#include <stdio.h>
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
9.实现细节
获取一个流所对应的文件描述符
#include <stdio.h>
int fileno(FILE *fp);
//返回与流相关的文件描述符
10.临时文件
创建临时文件
#include <stdio.h>
char tmpnam(char *ptr);
//返回唯一路径名的指针
FILE *tmpfile(void);
//成功返回文件指针,失败返回NULL
每次调用tmpnam返回一个与文件名不同的有效路径名字符串
tmpfile产生一个临时的二进制文件(wb+)。在关闭该文件或程序结束的时候将自动删除这个文件。