预计阅读本页时间:-
4.1.7 使用文件系统调用的一个示例程序
本节会考察一个简单的UNIX程序,它把文件从源文件处复制到目标文件处。程序清单如图4-5所示。该程序的功能很简单,甚至没有考虑出错报告处理,但它给出了有关文件的系统调用是怎样工作的一般思路。
例如,通过下面的命令行可以调用程序copyfile:
copyfile abc xyz
广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元
把文件abc复制到xyz。如果xyz已经存在,abc会覆盖它。否则,就创建它。程序调用必须提供两个参数,它们都是合法的文件名。第一个是源文件;第二个是输出文件。
在程序的开头是四个#include语句,它们把大量的定义和函数原型包含在这个程序。为了使程序遵守相应的国际标准,这些是需要的,无须作进一步的讨论。接下来一行是main函数的原型,这是ANSI C所必需的,但对我们的目的而言,它也不是重点。
接下来的第一个#define语句是一个宏定义,它把BUF_SIZE字符串定义为一个宏,其数值为4096。程序会读写若干个有4096个字节的块。类似地,给常数一个名称而且用这一名称代替常数是一种良好的编程习惯。这样的习惯不仅使程序易读,而且使程序易于维护。第二个#define语句决定谁可以访问输出文件。
主程序名为main,它有两个参数:argc和argv。当调用这个程序时,操作系统提供这两个参数。第一个参数表示在调用该程序的命令行中包含多少个字符串,包括该程序名。它应该是3。第二个参数是指向程序参数的指针数组。在上面的示例程序中,这一数组的元素应该包含指向下列值的指针:
argv[0]="copyfile"
argv[1]="abc"
argv[2]="xyz"
正是通过这个数组,程序访问其参数。
声明了五个变量。前面两个(in_fd和out_fd)用来保存文件描述符,即打开一个文件时返回一个小整数。后面两个(rd_count和wt_count)分别是由read和write系统调用所返回的字节计数。最后一个(buffer)是用于保存所读出的数据以及提供写入数据的缓冲区。
第一行实际语句检查argc,看它是否是3。如果不是,它以状态码1退出。任何非0的状态码均表示出错。在本程序中,状态码是惟一的出错报告处理。一个程序的产品版通常会打印出错信息。
接着我们试图打开源文件并创建目标文件。如果源文件成功打开,系统会给in_fd赋予一个小的整数,用以标识源文件。后续的调用必须引用这个整数,使系统知道需要的是哪一个文件。类似地,如果目标文件也成功地创建了,out_fd会被赋予一个标识用的值。create的第二个变量是设置保护模式。如果打开或创建文件失败,对应的文件描述符被设为-1,程序带着出错码退出。
接下来是用来复制文件的循环。一开始试图读出4KB数据到buffer中。它通过调用库过程read来完成这项工作,该过程实际激活了read系统调用。第一个参数标识文件,第二个参数指定缓冲区,第三个参数指定读出多少字节。赋予rd_count的字节数是实际所读出的字节数。通常这个数是4096,除非文件中只有少量字节。当到达文件尾部时,该参数的值是0。如果rd_count是零或负数,复制工作就不能再进行下去,所以执行break语句,用以中断循环(否则就无法结束了)。
调用write把缓冲区的内容输出到目标文件中去。第一个参数标识文件,第二个参数指定缓冲区,第三个参数指定写入多少字节,同read类似。注意字节计数是实际读出的字节数,不是BUF_SIZE。这一点是很重要的,因为最后一个缓冲区一般不会是4096,除非文件长度碰巧是4KB的倍数。
当整个文件处理完时,超出文件尾部的首次调用会把0值返回给rd_count,这样,程序会退出循环。此时,关闭两个文件,程序退出并附有正常完成的状态码。
尽管Windows的系统调用与UNIX的系统调用不同,但是Windows程序复制文件的命令行的一般结构与图4-5中的相当类似。我们将在第11章中考察Windows Vista的系统调用。
