UNP第五章 标准I/O库

流和FILE对象

在第三章中,所有I/O函数都是不带缓冲的。术语不带缓冲指的是每个read和write都调用内核中的一个系统调用。而对于标准I/O库,它们的操作是围绕流进行的:当用标准I/O库打开或创建一个文件时,我们已使一个流与一个文件关联。
关于流的概念,个人理解流是对于数据特殊操作,例如在读数据操作时读一点处理一点;在写数据操作里生成一点, 写入一点。

A stream is a logical interface to a file.

流的定向(stream’s orientation)决定了所读、写的字符是单字节还是多字节的。若在未定向的流上使用一个多字节I/O函数,则该流的定向设置为宽定向的;若在未定向的流上使用一个单字节的I/O函数,则该流的定向设置为字节定向的。

#include <stdio.h>
#include <wchar.h>
int fwide(FILE *fp, int mode);

fwide函数可以设置未定向的流的定向,mode为负数,指定为字节定向;mode为正数,指定为宽定向;mode为0,fwide将不试图设置流的定向。注意,fwide并不改变已定向流的定向。

标准输入、标准输出和标准错误

这三个流可以自动地被进程使用,这三个标准I/O流通过预定义在头文件

缓冲

标准I/O库提供缓冲的目的是尽可能减少使用read和write调用的次数,因为这两个函数都需要应用程序自定义用户缓冲。
标准I/O提供了以下三种类型的缓冲:

  1. 全缓冲:在填满标准I/O缓冲区后才进行实际的I/O操作。对于驻留在磁盘上的文件通常是由标准I/O库实施全缓冲的。
    flush:冲洗缓冲区操作。flush说明标准I/O缓冲区的写操作:在标准I/O库方面,flush意味着将缓冲区的内容写到磁盘上(该缓冲区可能未写满);在终端驱动程序方面,flush表示丢弃已存储在缓冲区的数据。
  2. 行缓冲:在输入和输出中遇到换行符时,标准I/O库执行I/O操作。这允许我们一次输出一个字符,但只有在写了一行之后才进行实际操作。
    对于行缓冲有两个限制:(1)因为标准I/O库用来收集每一行缓冲区的长度是固定的,所以只要填满了缓冲区,那么即使还没有写一个换行符,也进行I/O操作(这点类似全缓冲);(2)任何时候只要通过标准I/O库要求从a.一个不带缓冲的流b.一个行缓冲的流中得到数据,那么就会冲洗所有行缓冲输出流。–》从一个不带缓冲的流中得到数据,即是说数据要从内核获得。
  3. 不带缓冲:标准I/O库不对字符进行缓冲存储。标准错误流stderr通常是不带缓冲的,这就使得错误信息可以尽快显示出来,而不管它们是否包含一个换行符。不带缓冲的情况下可以使得字符尽快得到输入或输出。

更改缓冲类型

#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

setbuf

setbuf可以用来打开或关闭缓冲机制。为了带缓冲进行I/O,参数buf必须指向一个长度为BUFSIZ的缓冲区(通常情况下指定之后该流为全缓冲的,但该流的关联文件如果是终端设备,那么某些系统也可以将其设置为行缓冲的);为了关闭缓冲,将buf设置为NULL。

setvbuf

setvbuf可以精确地说明所需的缓冲类型,mode

  • _IOFBF:FULL BUF全缓冲
  • _IOLBF:LINE BUF行缓冲
  • _IONBF:NONE BUF不缓冲
int fflush(FILE *fp);

此函数使该流所有未写的数据都被传送至内核;若fp为NULL,则此函数将导致所有输出流被冲洗。

打开流

#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);
  1. fopen函数打开路径名为pathname的一个指定的文件
  2. freopen函数在一个指定的流上打开一个指定的文件,若流已经打开,则先关闭流
  3. fdopen函数取一个已有的文件描述符。此函数常用于创建管道和网络通信通道函数返回的描述符,因为这些特殊类型的文件不能用标准I/O函数fopen打开,我们必须先调用设备专用函数以获得一个文件描述符,然后用fdopen使一个标准I/O流与该描述符相结合
FILE *fp = fopen("/Users/hupac/Public/k.c", "rb");
//为打开文件关联一个流

读和写流

  1. 每次一个字符的I/O:
int getc(FILE *fp);
int fgetc(FILE *fp);
int getchar(void);

int k = getc(stdin);
putc(k, stdout);
//利用整型变量k来获取从fp指向文件中的一个字符,并用标准输出打印

getc和fgetc的区别在于,前者可以实现为宏,而后者不能实现为宏。宏函数作为预处理命令,调用函数所需的时间通常长于宏。

#define f(fp) getc(fp)

从流中读取数据后,可以调用ungetc将字符再压送回流中。但读入字符的顺序与压送回的顺序相反。

#include <stdio.h>
int ungetc(int c, FILE *fp);

示例:往标准输入中压送一个字符

    //测试ungetc(int, FILE)
    int in1 = getc(stdin);
    putchar(in1);
    int in2 = getc(stdin);
    putchar(in2);
    ungetc(in1, stdin);
    ungetc(in2, stdin);
    int  out1 = getc(stdin);
    int  out2 = getc(stdin);
    putchar(out1);
    putchar(out2);

结果:12回车
1221
分析:第一个ungetc把输入的1压入stdin,第二个ungetc把输入的2压入stdin,然后输出的顺序为2,1。从而得到结论压送回到流中的字符以后又可以从流中读出,但读出字符的顺序与压送回的顺序相反。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值