没有合适的资源?快使用搜索试试~ 我知道了~
UNIX环境高级编程-005_标准IO库
需积分: 0 1 下载量 121 浏览量
2009-12-08
12:54:42
上传
评论
收藏 537KB PDF 举报
温馨提示
试读
19页
UNIX环境高级编程一套电子书! 一共23部分19章。最后4部分为:函数原型、其它源码、习题答案、参考资料 如果您对某章节感兴趣,则下载非常方便! 如果此资源有侵权,请通知我,我会及时撤销下载!
资源详情
资源评论
资源推荐
下载
第5章 标 准 I/O 库
5.1 引言
本章说明标准 I / O 库。因为不仅在 U N I X 而且在很多操作系统上都实现此库,所以它由
ANSI C标准说明。标准I / O库处理很多细节,例如缓存分配,以优化长度执行 I / O 等。这样使用
户不必担心如何选择使用正确的块长度(如 3 . 9节中所述)。标准I / O库是在系统调用函数基础上
构造的,它便于用户使用,但是如果不较深入地了解库的操作,也会带来一些问题。
标准I / O 库是由Dennis Ritchie在1 9 7 5年左右编写的。它是由 Mike Lesk编写的
可移植I / O 库的主要修改版本。令人惊异的是, 1 5 年后制订的标准I / O 库对它只作
了极小的修改。
5.2 流和F I L E对象
在第3章中,所有I / O函数都是针对文件描述符的。当打开一个文件时,即返回一个文件描
述符,然后该文件描述符就用于后读的 I / O 操作。而对于标准 I / O 库,它们的操作则是围绕流
(s t r e a m)进行的(请勿将标准I / O 术语流与系统V的STREAMS I/O系统相混淆)。当用标准I / O
库打开或创建一个文件时,我们已使一个流与一个文件相结合。
当打开一个流时,标准I / O函数f o p e n返回一个指向F I L E对象的指针。该对象通常是一个结
构,它包含了I / O 库为管理该流所需要的所有信息:用于实际 I / O 的文件描述符,指向流缓存的
指针,缓存的长度,当前在缓存中的字符数,出错标志等等。
应用程序没有必要检验 F I L E 对象。为了引用一个流,需将 F I L E指针作为参数传递给每个
标准I / O函数。在本书中,我们称指向F I L E对象的指针(类型为F I L E
*
)为文件指针。
在本章中,我们以U N I X系统为例,说明标准I / O库。正如前述,此标准库已移到除U N I X以
外的很多系统中。但是为了说明该库实现的一些细节,我们选择U N I X实现作为典型进行介绍。
5.3 标准输入、标准输出和标准出错
对一个进程预定义了三个流,它们自动地可为进程使用:标准输入、标准输出和标准出错。
在3 . 2节中我们曾用文件描述符S T D I N _ F I L E N O , S T D O U T _ F I L E N O和S T D E R R _ F I L E N O分别表
示它们。
这三个标准I / O 流通过预定义文件指针 s t d i n , s t d o u t 和s t d e r r 加以引用。这三个文件指针同样
定义在头文件< s t d i o . h >中。
5.4 缓存
标准I / O 提供缓存的目的是尽可能减少使用 r e a d和w r i t e 调用的数量(见表3 - 1,其中显示了
在不同缓存长度情况下,为执行 I / O所需的C P U 时间量)。它也对每个I / O流自动地进行缓存管
理,避免了应用程序需要考虑这一点所带来的麻烦。不幸的是,标准 I / O 库令人最感迷惑的也
是它的缓存。
标准I / O提供了三种类型的缓存:
(1) 全缓存。在这种情况下,当填满标准I / O 缓存后才进行实际I / O操作。对于驻在磁盘上的
文件通常是由标准I / O库实施全缓存的。在一个流上执行第一次 I / O操作时,相关标准I / O 函数通
常调用m a l l o c(见7 . 8节)获得需使用的缓存。
术语刷新(f l u s h )说明标准I / O缓存的写操作。缓存可由标准 I / O 例程自动地刷新(例如当
填满一个缓存时),或者可以调用函数 ff l u s h 刷新一个流。值得引起注意的是在 U N I X 环境中,
刷新有两种意思。在标准 I / O 库方面,刷新意味着将缓存中的内容写到磁盘上(该缓存可以只
是局部填写的)。在终端驱动程序方面(例如在第 11章中所述的t c f l u s h函数),刷新表示丢弃已
存在缓存中的数据。
(2) 行缓存。在这种情况下,当在输入和输出中遇到新行符时,标准 I / O 库执行I / O操作。这
允许我们一次输出一个字符(用标准 I/O fputc函数),但只有在写了一行之后才进行实际 I / O操
作。当流涉及一个终端时(例如标准输入和标准输出),典型地使用行缓存。
对于行缓存有两个限制。第一个是:因为标准 I / O 库用来收集每一行的缓存的长度是固定
的,所以只要填满了缓存,那么即使还没有写一个新行符,也进行 I / O 操作。第二个是:任何
时候只要通过标准输入输出库要求从 ( a ) 一个不带缓存的流,或者 ( b )一个行缓存的流(它预先
要求从内核得到数据)得到输入数据,那么就会造成刷新所有行缓存输出流。在 ( b ) 中带了一
个在括号中的说明的理由是,所需的数据可能已在该缓存中,它并不要求内核在需要该数据时
才进行该操作。很明显,从不带缓存的一个流中进行输入( ( a )项)要求当时从内核得到数据。
(3) 不带缓存。标准I / O库不对字符进行缓存。如果用标准 I / O 函数写若干字符到不带缓存
的流中,则相当于用 w r i t e 系统调用函数将这些字符写至相关联的打开文件上。标准出错流
s t d e r r 通常是不带缓存的,这就使得出错信息可以尽快显示出来,而不管它们是否含有一个新
行字符。
ANSI C要求下列缓存特征:
(1) 当且仅当标准输入和标准输出并不涉及交互作用设备时,它们才是全缓存的。
(2) 标准出错决不会是全缓存的。
但是,这并没有告诉我们如果标准输入和输出涉及交互作用设备时,它们是不带缓存的还
是行缓存的,以及标准输出是不带缓存的,还是行缓存的。 S V R 4 和4 . 3 + B S D 的系统默认使用
下列类型的缓存:
• 标准出错是不带缓存的。
• 如若是涉及终端设备的其他流,则它们是行缓存的;否则是全缓存的。
对任何一个给定的流,如果我们并不喜欢这些系统默认,则可调用下列两个函数中的一个
更改缓存类型:
#include <stdio.h>
void setbuf(FILE *f p, char *b u f) ;
int setvbuf(FILE *
f p, char *b u f , int m o d e , size_t s i z e ) ;
返回:若成功则为0,若出错则为非0
这些函数一定要在流已被打开后调用(这是十分明显的,因为每个函数都要求一个有效的文件
9 2 U N I X 环境高级编程
下载
指针作为它们的第一个参数),而且也应在对该流执行任何一个其他操作之前调用。
可以使用s e t b u f函数打开或关闭缓存机制。为了带缓存进行 I / O,参数buf 必须指向一个长
度为B U F S I Z 的缓存(该常数定义在< s t d i o . h >中)。通常在此之后该流就是全缓存的,但是如果
该流与一个终端设备相关,那么某些系统也可将其设置为行缓存的。为了关闭缓存,将 b u f设
置为N U L L。
使用s e t v b u f,我们可以精确地说明所需的缓存类型。这是依靠 m o d e 参数实现的:
_IOFBF 全缓存
_IOLBF 行缓存
_IONBF 不带缓存
如果指定一个不带缓存的流,则忽略 buf 和size 参数。如果指定全缓存或行缓存,则 buf 和s i z e
可以可选择地指定一个缓存及其长度。如果该流是带缓存的,而 buf 是N U L L,则标准I / O 库将
自动地为该流分配适当长度的缓存。适当长度指的是由 s t r u c t结构中的成员s t _ b l k s i z e 所指定的
值(见4 . 2节)。如果系统不能为该流决定此值(例如若此流涉及一个设备或一个管道),则分
配长度为B U F S I Z的缓存。
伯克利系统首先使用s t _ b l k s i z e 表示缓存长度。较早的系统 V版本使用标准I / O
常数B U F S I Z(其典型值是1 0 2 4)。即使4 . 3 + B S D使用s t _ b l k s i z e决定最佳的I / O缓存
长度,它仍将B U F S I Z 设置为1 0 2 4。
表5 - 1 列出了这两个函数的动作,以及它们的各个选择项。
表5-1 setbuf 和setvbuf 函数
函 数 m o d e b u f 缓存及长度 缓存的类型
s e t b u f
n o n n u l l 长度为B U F S I Z 的用户缓存 全缓存或行缓存
N U L L (无缓存) 不带缓存
_ I O F B F
n o n n u l l 长度为s i z e 的用户缓存
全缓存
N U L L 合适长度的系统缓存
s e t v b u f
_ I O L B F
n o n n u l l 长度为s i z e的用户缓存
行缓存
N U L L 合适长度的系统缓存
_ I O N B F 忽略 无缓存 不带缓存
要了解,如果在一个函数中分配一个自动变量类的标准 I / O缓存,则从该函数返回之前,
必须关闭该流。(7 . 8节将对此作更多讨论。)另外,S V R 4 将缓存的一部分用于它自己的管理操
作,所以可以存放在缓存中的实际数据字节数少于 s i z e。一般而言,应由系统选择缓存的长度,
并自动分配缓存。在这样处理时,标准I / O库在关闭此流时将自动释放此缓存。
任何时候,我们都可强制刷新一个流。
# i n c l u d e < s t d i o . h >
int fflush(FILE *f p ) ;
返回:若成功则为0,若出错则为E O F
第 5章 标 准 I/O 库 9 3
下载
此函数使该流所有未写的数据都被传递至内核。作为一种特殊情形,如若 f p是N U L L,则此函
数刷新所有输出流。
传送一个空指针以强迫刷新所有输出流,这是由 ANSI C新引入的。非ANSI C
库(例如较早的系统V版本和4 . 3 B S D )并不支持此种特征。
5.5 打开流
下列三个函数可用于打开一个标准I / O流。
#include <stdio.h>
FILE *fopen(const char *p a t h n a m e, const char *t y p e) ;
FILE *freopen(const char *p a t h n a m e, const char *t y p e, FILE *f p) ;
FILE *fdopen(int f i l e d e s, const char *t y p e) ;
三个函数的返回:若成功则为文件指针,若出错则为 N U L L
这三个函数的区别是:
(1) fopen打开路径名由pathname 指示的一个文件。
(2) freopen在一个特定的流上(由f p指示)打开一个指定的文件(其路径名由pathname 指示),
如若该流已经打开,则先关闭该流。此函数一般用于将一个指定的文件打开为一个预定义的流:
标准输入、标准输出或标准出错。
(3) fdopen取一个现存的文件描述符(我们可能从 o p e n , d u p , d u p 2 , f c n t l或p i p e函数得到此文
件描述符),并使一个标准的I / O 流与该描述符相结合。此函数常用于由创建管道和网络通信通
道函数获得的插述符。因为这些特殊类型的文件不能用标准 I/O fopen函数打开,首先必须先调
用设备专用函数以获得一个文件描述符,然后用 f d o p e n使一个标准I / O 流与该描述符相结合。
f o p e n和f r e o p e n是ANSI C的所属部分。而ANSI C并不涉及文件描述符,所以
仅有P O S I X . 1具有f d o p e n。
t y p e参数指定对该I / O流的读、写方式,ANSI C规定t y p e参数可以有1 5种不同的值,它们示
于表5 - 2中。
表5-2 打开标准I / O流的t y p e 参数
t y p e 说 明
r 或 r b 为读而打开
w 或 w b 使文件成为0长,或为写而创建
a 或 a b 添加;为在文件尾写而打开,或为写而创建
r+ 或 r+b 或 r b + 为读和写而打开
w+ 或 w+b 或 w b + 使文件为0长,或为读和写而打开
a+ 或 a+b 或 a b + 为在文件尾读和写而打开或创建
9 4 U N I X环境高级编程
下载
剩余18页未读,继续阅读
Tech-Worm
- 粉丝: 18
- 资源: 39
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- 装修通用报价参考,基础施工项目+水电工程项目+瓦木项目,超级详细
- 三菱PLC例程源码Medocsequencegenerator
- 三菱PLC例程源码M1320磨头进出FX1s控制步进电机,有注释
- STRASSEN矩阵乘法算法(改进分治法·C语言)
- 前端.xmind前端.xmind前端.xmind前端.xmind前端.xmind
- 三菱PLC例程源码LOW-E玻璃镀膜线程序(三菱QPLC的)一万步带注释
- 三菱PLC例程源码LCD设备蚀刻机程序
- 三菱PLC例程源码LCD设备蚀刻机
- 全面前端开发指南:从基础到深入
- pvk2pfx 32位 Pvk2Pfx (Pvk2Pfx.exe) 是一种命令行工具,可将 .spc、.cer 和 .pvk 文
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功
评论0