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