unix高级程序设计

上传人:xzh****18 文档编号:46621420 上传时间:2018-06-27 格式:PDF 页数:19 大小:770.84KB
返回 下载 相关 举报
unix高级程序设计_第1页
第1页 / 共19页
unix高级程序设计_第2页
第2页 / 共19页
unix高级程序设计_第3页
第3页 / 共19页
unix高级程序设计_第4页
第4页 / 共19页
unix高级程序设计_第5页
第5页 / 共19页
点击查看更多>>
资源描述

《unix高级程序设计》由会员分享,可在线阅读,更多相关《unix高级程序设计(19页珍藏版)》请在金锄头文库上搜索。

1、下载第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

2、/ 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库为管理该流所需要的所有信息:用

3、于实际 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 标准输入、标准输出和标准出错对一个进程预定义了三个流,它们自动地可为进程使用:标准输入

4、、标准输出和标准出错。 在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加以引用。这三个文件指针同样 定义在头文件中。5.4 缓存标准I / O提供缓存的目的是尽可能减少使用 r e a d和w r i t e调用的数量(见表3 - 1,其中显示了 在不同缓存长度情况下,为执行 I / O所需的C P U时间量) 。它也对每个I

5、/ 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

6、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操 作。当流涉及一个终端时(例如标准输入和标准输出) ,典型地使用行缓存。 对于行缓存有两个限制。第一个是:

7、因为标准 I / O库用来收集每一行的缓存的长度是固定 的,所以只要填满了缓存,那么即使还没有写一个新行符,也进行 I / O操作。第二个是:任何 时候只要通过标准输入输出库要求从 ( a )一个不带缓存的流,或者 ( b )一个行缓存的流(它预先 要求从内核得到数据)得到输入数据,那么就会造成刷新所有行缓存输出流。在 ( b )中带了一 个在括号中的说明的理由是,所需的数据可能已在该缓存中,它并不要求内核在需要该数据时 才进行该操作。很明显,从不带缓存的一个流中进行输入( ( a )项)要求当时从内核得到数据。 (3) 不带缓存。标准I / O库不对字符进行缓存。如果用标准 I / O函数写

8、若干字符到不带缓存 的流中,则相当于用 w r i t e系统调用函数将这些字符写至相关联的打开文件上。标准出错流 s t d e r r通常是不带缓存的,这就使得出错信息可以尽快显示出来,而不管它们是否含有一个新 行字符。 ANSI C要求下列缓存特征: (1) 当且仅当标准输入和标准输出并不涉及交互作用设备时,它们才是全缓存的。 (2) 标准出错决不会是全缓存的。 但是,这并没有告诉我们如果标准输入和输出涉及交互作用设备时,它们是不带缓存的还 是行缓存的,以及标准输出是不带缓存的,还是行缓存的。 S V R 4和4 . 3 + B S D的系统默认使用 下列类型的缓存: 标准出错是不带缓存

9、的。 如若是涉及终端设备的其他流,则它们是行缓存的;否则是全缓存的。 对任何一个给定的流,如果我们并不喜欢这些系统默认,则可调用下列两个函数中的一个 更改缓存类型:#include 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 2U N I X环境高级编程下载指针作为它们的第一个参数) ,而且也应在对该流执行任何一

10、个其他操作之前调用。 可以使用s e t b u f函数打开或关闭缓存机制。为了带缓存进行 I / O,参数buf 必须指向一个长 度为B U F S I Z的缓存(该常数定义在中) 。通常在此之后该流就是全缓存的,但是如果 该流与一个终端设备相关,那么某些系统也可将其设置为行缓存的。为了关闭缓存,将 b u f设 置为N U L L。 使用s e t v b u f,我们可以精确地说明所需的缓存类型。这是依靠m o d e参数实现的:_IOFBF 全缓存 _IOLBF 行缓存 _IONBF 不带缓存如果指定一个不带缓存的流,则忽略buf 和size 参数。如果指定全缓存或行缓存,则buf 和

11、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

12、 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 eb u f缓存及长度缓存的类型s e t b u fn o n n u l l长度为B U F S I Z的用户缓存全缓存或行缓存N U L L(无缓存)不带缓存_ I O F B Fn 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 Fn o n n u l l长度为s i

13、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 int fflush(FILE *f p) ;返回:若成功则为0,

14、若出错则为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 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

15、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取一个现存的文件

16、描述符(我们可能从 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

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 行业资料 > 其它行业文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号