您的位置:首页 > 其它

UNP第五章 标准I/O库

2017-07-22 14:52 183 查看

流和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提供了以下三种类型的缓冲:

全缓冲:在填满标准I/O缓冲区后才进行实际的I/O操作。对于驻留在磁盘上的文件通常是由标准I/O库实施全缓冲的。

flush:冲洗缓冲区操作。flush说明标准I/O缓冲区的写操作:在标准I/O库方面,flush意味着将缓冲区的内容写到磁盘上(该缓冲区可能未写满);在终端驱动程序方面,flush表示丢弃已存储在缓冲区的数据。

行缓冲:在输入和输出中遇到换行符时,标准I/O库执行I/O操作。这允许我们一次输出一个字符,但只有在写了一行之后才进行实际操作。

对于行缓冲有两个限制:(1)因为标准I/O库用来收集每一行缓冲区的长度是固定的,所以只要填满了缓冲区,那么即使还没有写一个换行符,也进行I/O操作(这点类似全缓冲);(2)任何时候只要通过标准I/O库要求从a.一个不带缓冲的流或b.一个行缓冲的流中得到数据,那么就会冲洗所有行缓冲输出流。–》从一个不带缓冲的流中得到数据,即是说数据要从内核获得。

不带缓冲:标准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);


fopen函数打开路径名为pathname的一个指定的文件

freopen函数在一个指定的流上打开一个指定的文件,若流已经打开,则先关闭流

fdopen函数取一个已有的文件描述符。此函数常用于创建管道和网络通信通道函数返回的描述符,因为这些特殊类型的文件不能用标准I/O函数fopen打开,我们必须先调用设备专用函数以获得一个文件描述符,然后用fdopen使一个标准I/O流与该描述符相结合

FILE *fp = fopen("/Users/hupac/Public/k.c", "rb");
//为打开文件关联一个流


读和写流

每次一个字符的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 =
4000
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。从而得到结论压送回到流中的字符以后又可以从流中读出,但读出字符的顺序与压送回的顺序相反。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  io 函数