一、定义:标准I/O是标准C库提供的对文件操作的函数接口
二、常见的标准I/O函数:
1、fopen()
函数原型:FILE *fopen(const char *path,const char *mode)
函数功能:以指定的mode打开指定的流path(注:流就是我们要操作的文件的地址)
返回值:成功则返回指向该流的文件指针,失败则返回NULL,并将错误代码存于error中
常用的mode:
“r”:只读方式打开,打开的文件必须存在
“r+”:读写方式打开,文件必须存在
“w”:只写方式打开,文件不存在则创建,文件存在则清空
“w+”:读写方式打开,文件不存在则创建,文件存在则清空
“a”:只写方式打开,文件不存在则创建,文件存在则将数据追加到文件尾部
“a+”:读写方式打开,文件不存在则创建,文件存在则将数据追加到文件尾部
“rb+”:读写方式打开一个二进制文件,文件必须存在
“rt+”:读写方式打开一个文本文件,文件必须存在
“wb+”:只写方式打开一个二进制文件,文件不存在则创建,文件存在则清空
“wt+”:只写方式打开一个文本文件,文件不存在则创建,文件存在则清空
“ab+”:读写方式打开一个二进制文件,文件不存在则创建,文件存在则将数据追加到文件尾部
“at+”:读写方式打开一个文本文件,文件不存在则创建,文件存在则将数据追加到文件尾部
2、单字符读/写函数:
fgetc()/fputc()
函数原型:int fgetc(FILE *stream)/ int fputc(FILE* stream)
函数功能:从指定的流中读/写一个字符
返回值:成功则返回读/写的字符,失败则返回EOF(-1),对于fgetc(),读到文件末尾也返回EOF
注:返回类型为int是为了能表示EOF,即-1
3、多字符读函数:
fgets()
函数原型:char *fgets(char *buf,int bufsize,char *stream)
函数功能:从指定的流stream中读取指定大小bufsize-1的字符到buf中
返回值:成功或读到文件尾但读入了字符则返回buf,失败或读到文件尾但未读入任何字符则返回NULL
注:fgets函数最多只能读取bufsize-1个字符,在读取结束时,会自动在字符末尾加上一个‘\0’,如果
读取的字符大小bufsize大于该行剩余字符总数时(至少大于2,一个保存字符串结束标识符‘\0’,一个保存换行符‘\n’),
文件将停止读取下一行
4、多字符写函数:
fputs()
函数原型:int fputs(const char *s,FILE *stream)
函数功能:将一个字符串写入到指定的文件中,s为字符串首地址,stream为要写入字符串的流
返回值:成功则返回写入字符的个数,失败则返回-1
注:将字符串写入文件时,若果碰到‘\0’,则停止写入
5、fread()/ fwrite()
函数原型:size_t fread(void *buffer,size_t size,size_t count,FILE *stream)
size_t fread(const void *buffer,size_t size,size_t count,FILE *stream)
函数功能:fread 从指定的流中读取count个size大小的项到buffer中
fwrite 向指定的流中写入count个size大小的项
返回值:成功则返回真实读取/写入的项数,失败则返回0
6、fseek()
函数原型:int fseek(FILE *stream,long offset,int fromwhere)
函数功能:重定位流(数据流/文件)中的内部指针
返回值:成功则返回0,失败则返回1,并设置error的值,可用perror()函数输出错误
offset:整数表示正向偏移量,负数表示负向偏移量
fromwhere:文件头 SEEK_SET(0)、当前位置 SEEK_CUR(1)、文件尾 SEEK_END(2)
注:fseek中的文件指针,应该指向已经打开的文件,否则会发生错误。如果执行成功,位置指针将指向以fromwhere(偏移起始位置)为基准,偏移offset个字节的位置。如果执行失败,比如offset超过文件自身大小,则不改变位置指针指向的位置
7、fdopen()/ fileno()
函数原型:FILE *fdopen(int fildes,const char *mode)
int fileno(FILE *stream)
函数功能:fdopen 将文件描述符转换为指定模式的FILE文件指针
fileno 将文件指针转换为文件描述符
返回值:fdopen 成功返回转换的结构体指针,失败返回NULL
fileno 成功返回转换后的文件描述符,失败返回-1
注:上述参数mode的选择与fopen函数的打开方式相同
文件描述符:由无符号整数表示,进程用它来表示打开的文件,内核用它来访问文件,其中0、1、2分别表示标准输入,标准输出,标准错误
8、fflush()
函数原型:int fflush(FILE *stream)
函数功能:清除读写缓冲区,强制将缓冲区内的数据写回参数stream指定的文件中,如果参数为NULL,fflush()会将所有打开的文件更新
返回值:成功刷新返回0,指定的流没有缓冲区或只读打开时也返回0.出错时返回EOF
9、feof()
函数原型:int feof(FILE *stream)
函数功能:检查文件流是否读到了尾
返回值:文件结束则返回非零值,否则返回0
10、fclose()
函数原型:int fclose(FILE *stream)
函数功能:关闭一个流
返回值:成功返回0,失败返回EOF
三、标准I/O函数的两个优点:
1、具有良好的可移植性(portability)
为了支持所有操作系统(编译器),这些函数都是按照ANSI C标准定义的。
2、可以利用缓冲来提高性能
在创建套接字时,系统会生成用于I/O的缓冲,而这主要是为了实现TCP协议而设立的,使用标准I/O函数时,会得到额外的缓冲支持,而它的主要目的是为了提高性能。此时数据传输会经过两个缓冲。
性能的提高主要从两方面体现,一方面为传输的数据量。比较一个字节的数据发送10次(10个数据包)的情况和累计10个字节发送1次的情况,发送的数据包中含有头信息,其与数据大小无关,固定格式。即使假设该头信息占用40个字节(实际更大),有无额外的缓冲时需要传递的数据量也会存在360个字节的差别。另一方面是数据向输出缓冲移动的次数。这中间消耗的时间也会有较大的差别。
四、标准函数的几个缺点:
1、不容易进行双向通信
2、有时可能频繁调用fflush函数
3、需要以FILE结构体指针的形式返回文件描述符
打开文件时,如果希望同时进行读写操作,则应以r+、w+、a+模式打开,但因为缓冲的缘故,每次切换都写工作时应调用fflush函数,这会影响给予缓冲的性能提高。而且为了使用标准I/O函数,需要FILE结构体指针,而创建套接字时默认返回文件描述符,因此需要将文件描述符转换为FILE指针。