3.标准文件IO

标准IO库

标准IO库处理有很多细节,例如缓冲区分配、以优化的块长度执行IO等。

1.流和FILE对象

对于标准IO库,所有操作都是围绕进行的,当用标准IO库打开或创建一个文件时,就使一个流与一个文件相关联。

流的定向决定读写字符是单字节还是多字节字符集(多字节对应宽定向,单字节对应字节定向)。fwide用于设置流的定向:

#include <stdio.h>
#include <wchar.h>
int fwide(FILE *fp, int mode);
/* 返回值:宽定向为正值;字节定向为负值;流是未定向,返回0 */

由于fwide无出错返回,因此在调用fwide前先清除errno,从fwrite返回时,检查errno的值。

2.缓冲

为了不频繁使用writeread,标准IO库提供了缓冲:

  • 全缓冲,填满标准IO缓冲区后进行实际IO操作
  • 行缓冲,遇到换行符或者填满行缓冲区后进行操作
  • 不缓冲,不缓冲,直接输出

通过下列两个函数可以对缓冲类型进行修改:

#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,失败返回非0 */

使用mode参数说明所需的缓冲类型:

mode参数 类型
_IOFBF 全缓冲
_IOLBF 行缓冲
_IONBF 不缓冲

若不使用缓冲,则忽略bufsize参数。

3.打开流

下列3个函数用于打开流:

#include <stdio.h>
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 fd, const char *type);
/* 返回值:成功返回文件指针,失败返回NULL */

三者区别在于:

  • fopen 打开路径名为pathname的一个指定文件
  • freopen 在一个指定的流上打开一个指定的文件,若该流已经打开,则先关闭该流。若该流已经定向,则使用freopen清除该定向。此函数一般用于将指定文件打开为一个预定义的流:标准输入,输出和错误
  • fdopen取一个已有的文件描述符(可能从open,dup,pipe,socket得到此描述符),并使一个标准IO流与该描述符向结合。此函数常用于创建管道和网络通信管道函数返回的描述符。

使用fclose可以关闭一个打开的流,在文件被关闭前,冲洗缓冲中的输出数据,并丢弃缓冲区中任何输入数据,并且释放此缓冲区。

一个进程正常终止时,则所有带未写缓冲数据的标志IO都会被冲洗,所有打开的标准IO流都被关闭。

4.读和写流

打开流之后,可以对其进行读写操作。

输入函数

以下3个函数用于一次读一个字符:

#include <stdio.h> 
int getc(FILE *fp); 
int fgetc(FILE *fp); 
int getchar(void);
/* 返回值:成功返回下一个字符;若到达尾端或者出错返回EOF */

getchar等同于getc(stdin)。前两个函数区别在于,getc可被实现为宏,而fgetc不能,这就意味着:

  • getc的参数不应当具有副作用的表达式
  • fgetc一定是个函数,可以通过函数指针传递给另一个函数
  • 调用fgetc所需时间可能比getc更长

输出函数

对应输入函数都有一个输出函数:

#include <stdio.h>
int putc(int c, FILE *fp); 
int fputc(int c, FILE *fp); 
int putchar(int c);
/* 返回值:成功返回c,出错返回EOF*/

与输入函数一样,putchar(c)等同于putc(c,stdout)putc可以被实现为宏。

5.每次一行IO

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

#include <stdio.h>
char *fgets(char *restrict buf, int n, FILE *restrict fp); 
char *gets(char *buf);
/* 返回值:成返回buf;若到达尾端或者出错返回NULL*/

尽量使用fgets防止缓冲区溢出。

对应输出一行的功能:

#include <stdio.h>
int fputs(const char *restrict str, FILE *restrict fp); 
int puts(const char *str);
/* 返回值:成功返回非负值,出错返回EOF*/

fputs将一个null字节终止的字符串写到指定的流,puts除了null,随后添加了一个换行符到标准输出。

如果总是使用fgetsfputs,那么久会熟知在每行终止处我们必须字节处理换行符。

6.二进制IO

前面的输入函数只能一次性读取一个字节或者一行数据,为了获得整个结构,提供了下列两个函数用以执行二进制IO操作:

#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);

读写一个结构体,可以如下:

struct {
    short  count;
    long   total;
    char   name[NAMESIZE];
} item;
if (fwrite(&item, sizeof(item), 1, fp) != 1)
    err_sys("fwrite error");
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • tags:io categories:总结 date: 2017-03-28 22:49:50 不仅仅在JAVA领...
    行径行阅读 6,593评论 0 3
  • C/C++输入输出流总结 前两天写C++实习作业,突然发现I/O是那么的陌生,打了好长时间的文件都没有打开,今天终...
    LuckTime阅读 5,684评论 0 6
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 176,161评论 25 709
  • 最近几天忙着招待婆家的姐姐们。累!刚从河北回来,跑来跑去,脚,不再是我的了。夜晚没睡好,眼睛生痛。大家庭的热闹实在...
    老美子阅读 1,283评论 0 0

友情链接更多精彩内容