预计阅读本页时间:-
除了可移植性之外,标准I/O包相对于低级I/O有两点优势。第一,标准I/O包中包含很多专用的函数,可以方便地处理不同的I/O问题。例如,printf()将各种类型的数据转换成为适合终端的字符串输出。第二,对输入和输出进行了缓冲。也就是说,大块地转移信息(通常每次不少于512个字节),而不是每次一个字节进行转移。例如,当程序读入一个文件时,会把一大块数据复制到缓冲区(一块中介存储区)中。这种缓冲大大提高了数据传输率。随后程序就可以分析缓冲区中的个别字节。缓冲过程是在后台处理的,所以您会产生逐字节读取的错觉(也可以缓冲低级I/O,可是这需要您亲自完成其中的大部分工作)。程序清单13.1示范了如何使用标准I/O读取文件和统计文件中字符的个数。我们将在下几节中讨论程序清单13.1的特点(这个程序使用了命令行参数。如果您是一名Windows用户,可能需要在编译以后从MS-DOS窗口运行它。如果您是一名Macintosh用户,应按照第11章“字符串和字符串函数”以及Code Warrior文档中描述的方法,使用console.h头文件和ccommand()函数。或者也可以改动程序,使用puts()和gets()函数代替命令行参数以获取文件名)。
程序清单13.1 count.c程序
广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元
13.2.1 检查命令行参数
首先,程序清单13.1中的程序检查argc的值,查看是否有命令行参数。如果没有,程序打印一条用法提示然后退出。字符串argv[0]是该程序的名称。使用argv[0],而不是显式地使用程序名,则在您改变了可执行文件名后,错误消息也会随之自动改变。这一特点在像UNIX这种允许单个文件具有多个文件名的环境中也同样方便。但是要知道某些操作系统(比如MS-DOS 3.0之前的操作系统)不能识别argv[0],所以这一用法并非完全可移植。
exit()函数关闭所有打开的文件并终止程序。exit()函数的参数会被传递给一些操作系统,包括UNIX、Linux和MS DOS,以供其他程序使用。通常的约定是正常终止的程序传递值0,非正常终止的程序传递非0值。不同的退出值可以用来标识导致程序失败的不同原因。这也是UNIX和DOS编程的通常做法。但并非所有的操作系统都识别相同范围内的可能返回值。所以,ANSI C标准规定使用一个相当有限的最小范围。具体地,该标准要求使用值0或宏EXIT_SUCCESS来指示程序成功终止,使用宏EXIT_FAILURE指示程序非成功终止。这些宏和exit()原型在stdlib.h头文件中都可以找到。本书将遵循通常的约定使用整数退出值。但为了获得最大的可移植性,您应使用宏EXIT_SUCCESS和EXIT_FAILURE。
按照ANSI C,在最初调用的main()中使用return和调用exit()的效果相同。所以,在main()中我们一直使用的语句:
和下面这个语句的作用相同:
但要注意我们所说的是“最初调用”。如果main()在一个递归程序中,exit()仍然会终止程序;但return将控制权移交给递归的前一级,直到最初的那一级,此时return才会终止程序。return和exit()的另一个区别在于,即使在除main()之外的函数中调用exit(),它也将终止程序。
13.2.2 fopen()函数
接下来,程序使用fopen()打开文件。这一函数在stdio.h中声明。它的第一个参数是要打开的文件名;更确切地说,是包含该文件名的字符串的地址。第二个参数是用于指定文件打开模式的一个字符串。C库提供了一些可能的模式,如表13.1。
表13.1 fopen()函数的模式字符串
模式字符串 | 意 义 |
---|---|
“r” | 打开一个文本文件,可以读取文件 |
“w” | 打开一个文本文件,可以写入文件,先将文件的长度截为零。如果该文件不存在则先创建之 |
“a” | 打开一个文本文件,可以写入文件,向已有文件的尾部追加内容,如果该文件不存在则先创建之 |
“r+” | 打开一个文本文件,可以进行更新,也即可以读取和写入文件 |
“w+” | 打开一个文本文件,可以进行更新(读取和写入),如果该文件存在则首先将其长度截为零; 如果不存在则先创建之 |
“a+” | 打开一个文本文件,可以进行更新(读取和写入),向已有文件的尾部追加内容,如果该文 件不存在则先创建之;可以读取整个文件,但写入时只能追加内容 |
“rb”, “wb”, “ab”, “ab+”, “a+b”, “wb+7rd;, “w+b”, “ab+”, “a+b” | 与前面的模式相似,只是使用二进制模式而非文本模式打开文件 |
对于像Unix和Linux这样只有一种文件类型的系统,带b字母的模式和对应的不带b字母的模式是相同的。