刚刚完成了my_cp的另一个功能:将一个目录拷贝到指定目录。加上昨天实现的将一个文件拷贝到指定地址下,现在已经完成了我们实现前所定下的要求。也许你会有疑问,那多个文件的拷贝的实现呢?我面前面已经说过,只要完成上述两个功能,并且你在主函数中“分流”正确,那么只要在合适的位置调用这两个函数即可,具体办法我们下面会讨论。
在详解如何实现将一个目录拷贝到指定目录(cp_directory函数)之前,我们首先应该弄明白下面的内容:
1.如果目标目录中的最低级目录不存在,则会新建这个目录,并把源目录中的所有文件拷贝到此新建的目录下。比如cp -r dir ./newdir。我们可以看到./newdir(这个路径中最低级的目录是newdir)在cp前是不存在的,但是cp后新建了这个目录,并且将dir中的所有文件拷贝到这个新建的目录下。
1 | gues@huangwei-desktop:~/code/shell_command$ ls |
2 | cptest ls my_cp my_cp.c my_ls_plus my_shell.c nothisdirectory tdir test |
3 | dir ls1 my_cp1 my_ls.c my_ls_plus.c newdirectory nothisfile tdirmy_ls.c ttfile.c |
4 | gues@huangwei-desktop:~/code/shell_command$ ls dir |
5 | ed my_cp1 test ttfile.c |
6 | gues@huangwei-desktop:~/code/shell_command$ cp -r dir ./newdir |
7 | gues@huangwei-desktop:~/code/shell_command$ ls newdir |
8 | ed my_cp1 test ttfile.c |
2.如果最低级的目标目录存在,则会将源目录(当然也包含源目录下的所有文件)拷贝到这个目标目录。我们仍执行上面那个命令:cp -r dir ./newdir。但是这次结果是不一样的,由于1的操作,newdir目录已经存在,这次cp后将dir目录拷贝到了已存在的newdir目录下(即./newdir/dir/)。
1 | gues@huangwei-desktop:~/code/shell_command$ ls newdir |
2 | ed my_cp1 test ttfile.c |
3 | gues@huangwei-desktop:~/code/shell_command$ cp ./dir -r ./newdir |
4 | gues@huangwei-desktop:~/code/shell_command$ ls newdir |
5 | dir ed my_cp1 test ttfile.c |
如果我说的还不够明白,你也可以自己亲自验证一下cp命令。
下面我们来详解。还是先保留传递过来的路径。然后如果源文件夹不包含/,则添加。
01 | void cp_directory( char * original_src_path, char * original_dest_path) |
06 | char path[PATH_MAX+1]; |
07 | char src_path[PATH_MAX+1],dest_path[PATH_MAX+1]; |
09 | strcpy (src_path,original_src_path); |
10 | strcpy (dest_path,original_dest_path); |
12 | if (src_path[ strlen (src_path)-1]!= '/' ) |
14 | strncat (src_path, "/" ,1); |
如果目标目录中最低级的目录不存在,则创建它。如果次低级目录也不存在,则在创建的时候就发生错误。如果目标目录存在,并且是目录文件,那么就如同上面举例2中所述,我们需要将源路径中最低级的目录拷贝到目标目录中。这里面设计到提提取源路径最低级的目录,以及将其连接在目标目录后等。这些都不难理解。注意当完成目标路径的拼接后,如果这个目录本身就存在,那么我们将其删除,创建新目录。
01 | if (stat(dest_path,&buf)==-1) |
05 | if (mkdir(dest_path,buf.st_mode)==-1) |
07 | printf ( "my_cp:create the directory \"%s\" error.\n" ,dest_path); |
14 | if (!S_ISDIR(buf.st_mode)) |
16 | printf ( "my_cp:the directory \"%s\" can't cover the no-directory \"%s\".\n" ,src_path,dest_path); |
21 | if (dest_path[ strlen (dest_path)-1]!= '/' ) |
23 | strncat (dest_path, "/" ,1); |
27 | char lowestdir[PATH_MAX+1]; |
28 | for (i= strlen (src_path)-1-1;i>\0;i--) |
37 | for (;i<\ strlen (src_path);i++) |
39 | lowestdir[k++]=src_path[i]; |
41 | strncat (dest_path,lowestdir, strlen (lowestdir)); |
43 | char temp_path[PATH_MAX+1]= "rm -rf " ; |
44 | if (stat(dest_path,&temp_buf)==0) |
46 | strcat (temp_path,dest_path); |
49 | if (mkdir(dest_path,buf.st_mode)==-1) |
51 | printf ( "my_cp:create the directory \"%s\" error.\n" ,dest_path); |
接着我们打开源目录,读取其下的所有文件名。这个方法在my_ls的时候就已经使用过。我们将这些文件名与目的路径拼接后,检查他们是否是目录文件。如果是普通文件那么就调用cp_single函数,否则调用cp_directory函数。
01 | if ((dir=opendir(src_path))==NULL) |
03 | printf ( "my_cp:open the srouce path \"%s\" error.\n" ,src_path); |
06 | char temp_dest_path[PATH_MAX+1]; |
07 | strcpy (temp_dest_path,dest_path); |
08 | while ((ptr=readdir(dir))!=NULL) |
10 | if (! strcmp (ptr->\d_name, "." )) |
12 | if (! strcmp (ptr->\d_name, ".." )) |
14 | strcpy (path,src_path); |
15 | strcat (path,ptr->\d_name); |
16 | if (stat(path,&buf)==-1) |
18 | printf ( "my_cp:open the file \"%s\" error.\n" ,path); |
21 | strcpy (dest_path,temp_dest_path); |
23 | if (S_ISDIR(buf.st_mode)) |
25 | cp_directory(path,dest_path); |
29 | cp_single(path,dest_path); |
其实这是一个递归的过程,对于递归,最重要的是能返回到调用函数。对于任何目录,最终要么这个目录是空的,要么全是普通文件,所以肯定能返回到上一级函数中,不会无限的去嵌套。
以上就是my_cp函数的实现过程,需要源码的同学留下邮箱即可。如果发现了不妥之处,欢迎指正。
http://edsionte.com/techblog/archives/904