cp命令是经常使用的命令,复制文件,而构思它的编写过程也非常直观。把文件中的数据读出来,创建一个新文件,再把数据写进去。这就是一个很常规的思路。而在编写程序中思考的主要问题就是要全面,各种情况的输入都要考虑完全。
而打开文件,创建文件,读取文件数据,写入数据,关闭文件仍然是调用常见的内核函数open(),creat(),read(),write(),close()来完成。
代码较于之前写的命令较为简单。
因为此次cp命令涉及的可能出现错误指令比较多,例如:缺失源文件,目标文件,文件中无数据可读取等等,所以此次把报错信息封装成为一个函数。
36 void opps(char *s1,char *s2)
37 {
38 fprintf(stderr,"Error:%s",s1);
39 perror(s2);
40 exit(1);
41 }
对其他的文件操作都比较熟悉了,但是用到fprintf的时候查了它的定义还是没太看明白,自己做了小实验后可以把它理解为把第三项按照第二项的输出格式输出至第一项的文件中,在这里把它输出至标准错误流。而Perror比较熟悉了,把上个函数的错误原因输出至标准错误流。
接着看主函数:
10 int main(int ac,char *av[])
11 {
12 int in_fd,out_fd,n_chars;
13 char buf[BUFFERSIZE];
14
15 if(ac!=3)
16 {
17 fprintf(stderr,"usage:%s source destination\n",*av);
18 exit(1);
19 }
20
21 if((in_fd=open(av[1],O_RDONLY)) ==-1)
22 opps("Cannot open",av[1]);
23
24 if((out_fd=creat(av[2],COPYMODE)) ==-1)
25 opps("Cannot creat",av[2]);
26 while((n_chars=read(in_fd,buf,BUFFERSIZE))>0)
27 if(write(out_fd,buf,n_chars) != n_chars)
28 opps("Write error to",av[2]);
29 if(n_chars == -1)
30 opps("Read error from",av[1]);
31 if(close(in_fd) == -1||close(out_fd) ==-1)
32 opps("Error closing files","");
33
34 }
程序本身比较好理解,但是很巧妙的是使用了main函数参数的功能判断,自己写的话一定会引入其它变量进行标志位判断,参数问题在以前main函数相关问题中探讨过这里原理不再详说,可以看一下它的使用。
在判断命令格式是否正确时的判断if(ac!=3),本身运行时候ac已经是1了,而使用cp命令需要源文件与目标文件,所以这时ac的值当然为3,那么如果不为3怎么样呢?会输出usage:cp source destination,后面的指针始终指向存储参数数组的第一项也就是cp命令,这里很巧妙的运用了main函数的参数作为判断,不需要引入其它变量进行判断。
后面的不必多说,数组第二项存放的是源文件,第三项存放目标文件,那么在后面的判断中都可以采用av[i]来代替源文件与目标文件。可以说用了main函数参数实现了一劳永逸。
编译并运行代码后可以使用自己写的cp命令来复制文件咯。
当然这个程序还有一个非常值得借鉴的地方,定义了一个buffersize用于取出数据后暂时存放,也就是说规定了缓冲区,这不仅在平时编程中广泛用到,在内核中也是非常重要的机制。具体请参见系统编程一些提高小总结。