《UNIX环境高级编程》笔记 第五章-标准IO库

1. 流和FILE对象在第三章的系统调用都是围绕文件描述符fd的。但是标准I/O库函数操作则是围绕流进行的。当使用标准I/O库打开或创建一个文件时,使用一个流与一个文件关联。当打开一个流时,标准I/O函数fopen返回一个指向FILE对象的指针。FILE对象包含了标准I/O库为管理该流需要的所有信息,包括用于实际I/O的文件描述符、指向用于该流缓冲区的指针、缓冲区长度、当前缓冲区中字符数、出错标志等。我们称指向FILE对象的指针(FILE*)称为文件指针2. 标准输入、标准输出、标准错误对每个进程
摘要由CSDN通过智能技术生成

1. 流和FILE对象

在第三章的系统调用都是围绕文件描述符fd的。但是标准I/O库函数操作则是围绕流进行的。当使用标准I/O库打开或创建一个文件时,使用一个流与一个文件关联。

当打开一个流时,标准I/O函数fopen返回一个指向FILE对象的指针。FILE对象包含了标准I/O库为管理该流需要的所有信息,包括用于实际I/O的文件描述符、指向用于该流缓冲区的指针、缓冲区长度、当前缓冲区中字符数、出错标志等

我们称指向FILE对象的指针(FILE*)称为文件指针

2. 标准输入、标准输出、标准错误

对每个进程预定义了三个流:标准输入、标准输出、标准错误。这些流引用的文件与STDIN_FILENO、STDOUT_FILENO、STDERR_FILENO所引用的文件相同。

这三个标准I/O流分别是文件指针stdin、stdout、stderr

3. 缓冲

标准I/O库也是带缓冲的I/O,标准I/O库提供缓冲的目的是尽可能减少使用read和write调用的次数,减少用户态到内核态切换次数。它对每个I/O流自动进行缓冲管理,让应用程序不用考虑缓冲区大小、管理等问题。

缓冲是标准IO库提供的,缓冲区存在于用户空间(不管是fread还是fwrite)。在调用fwrite的时候,先把数据放在缓冲区。不直接使用系统调用,切换到内核态。而是等到缓冲区满或是调用fflush等条件满足时,再一次性调用write,把数据拷贝到内核空间。对于fread而言,就是在调用fread的时候,切换到内核态,内核态读取缓冲区能够接受的大小的数据, 然后返回给fread函数。下次再调用fread的时候,可能只需要从缓冲区读取,而不需要再到内核空间拷贝了

标准I/O提供了以下三种缓冲:

  • 全缓冲

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

  • 行缓冲

    当在输入和输出中遇到换行字符,标准I/O库进行实际I/O操作。比如我们每次输出一个字符(fputc),但是只有写了一行之后才进行实际I/O操作。

    当流涉及终端(如标准输入、标准输出)时,通常使用行缓冲

    只要填满了缓冲区,那么即使还没有写一个换行符也进行实际I/O

  • 不带缓冲

    标准错误流stderr通常不带缓冲,使得错误信息能够尽快显示出来,而不管是否有换行符。

冲洗flush:

冲洗表名标准I/O的写操作。缓冲区可由标准I/O例程自动冲洗(比如填满缓冲区时),或者调用fflush冲洗一个流。在标准I/O库中,flush(冲洗)意为将缓冲区中的内容写到磁盘上;在终端驱动程序方面,flush(刷清)表示丢弃已存储在缓冲区中的数据。

int fflush(FILE *stream);

使所有未写的(在缓冲区中的)数据都被传送至内核,如果stream是NULL,则导致所有输出流都被冲洗。

4. 更改流的缓冲类型

对于一个给定流,如果不喜欢系统默认的缓冲那个类型,可以修改缓冲类型

void setbuf(FILE *stream, char *buf);
int setvbuf(FILE *stream, char *buf, int mode, size_t size);

**函数setbuf:**主要用于打开和关闭缓冲机制

  • 如果要带缓冲,buf必须指向一个长度至少为 BUFSIZ 字节的缓冲区,BUFSIZ 是一个宏常量,表示数组的长度。通常在此之后该流就是全缓冲的,但是如果该流与一个终端设备相关,那么某些系统也可以将其设置为行缓冲。

    # define BUFSIZ _IO_BUFSIZ
    #define _IO_BUFSIZ _G_BUFSIZ
    #define _G_BUFSIZ 8192 // 可见BUFSIZ大小是8192字节
    
  • 如果不要缓冲,buf为NULL

**函数setvbuf:**可以精确指定缓冲类型

  • mode参数指定缓冲类型:
    • _IOFBF:全缓冲,buf和size指定缓冲区和缓冲区大小
    • _IOLBF:行缓冲,buf和size指定缓冲区和缓冲区大小
    • _IONBF:不带缓冲,忽略buf和size参数
  • 如果mode指定为带缓冲的,但是buf参数是nullptr,则会自动为该流分配一个适当长度的缓冲区(即由BUFSIZ指定的缓冲区长度,某些C库实现使用stat结构体的st_blksize成员决定最佳I/O缓冲区长度)

需要注意,某些实现将缓冲区的一部分用于存放它自己的管理操作信息,所以可以存放在缓冲区中的实际数据字节数少于size。

如果由标准I/O库自动分配缓冲区的话,关闭该流会导致自动释放缓冲区;如果是自己指定缓冲区的话,关闭该流不会释放缓冲区。

5. 打开流

通过以下函数打开一个标准I/O流

FILE *fopen(const char *pathname, const char *mode);
FILE *fdopen(int fd, const char *mode);
FILE *freopen(const char *pathname, const char *mode, FILE *stream);

fdopen:

取一个标准I/O流与一个已经打开的文件描述符相结合。常用于由管道和网络通信函数返回的描述符,因为这些特殊类型的文件不能用标准I/O函数fopen打开。所以需要先用设备专门函数(如socket)以获得一个文件描述符,然后用fdopen使一个标准I/O流与该描述符结合。

freopen:

把一个新的文件名 filename 与给定的打开的流 stream 关联,同时关闭流中的旧文件。常用于将一个指定的文件打开为一个预定义的流:stdin、stdout、stderr。文件重定向。

参数mode:

对I/O的读、写方式

mode 说明 open(2)标志
r或rb 以只读方式打开文件,该文件必须存在。 O_RDONLY
w或wb 打开只写文件,若文件存在则文件长度清为零,即该文件内容会消失;若文件不存在则创建该文件。 O_WRONLY | O_CREAT | O_TRUNC
a或ab 以附加的方式打开只写文件。若文件不存在,则会创建该文件;如果文件存在,则写入的数据会被加到文件尾后 O_WRONLY | O_CREAT | O_APPEND
r+或r+b或rb+ 以读/写方式打开文件,该文件必须存在。 O_RDWR
w+或w+b或wb+ 打开可读/写文件,若文件存在则文件长度清为零,即该文件内容会消失;若文件不存在则创建该文件。 O_RDWR | O_CREAT | O_TRUNC
a+或a+b或ab+ 以附加方式打开可读/写的文件。若文件不存在,则会创建该文件,如果文件存在,则写入的数据会被加到文件尾后 O_RDWR | O_CREAT | O_APPEND
  • 其中字符’b’用于标准I/O库区分文本文件和二进制文件。但是UNIX内核并不对这两种文件进行区分,因此UNIX环境中指定字符’b’无用

  • 如果有多个进程同时用标准I/O追加写相同文件,那么来自每个进程数据都会正确写入到文件中(即该函数是线程安全的)。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值