Welcome 微信登录
编程资源 图片资源库 蚂蚁家优选 PDF转换器

首页 / 操作系统 / Linux / Linux C实现cp功能

一:背景看了unix/linux编程实践,跟着书上代码实现了普通文件的拷贝,看到课后习题后需要实现目录之间的拷贝,因此有了本文,我最初实现cp用了180多行代码,后来觉得很多地方可以封装,但是最后居然越封装越多达到了200多行,今晚果断再次封装,修剪了代码大概170多行,要比课后答案的要简便点。该cp可以实现普通文件的拷贝,拷贝到指定目录下,和目录直接拷贝等功能。二:思路目录之间的拷贝我觉得最主要的功能就是path路径的拼装,处理好path路径问题,就很简单了。例如 /root/a.txt 拷贝到 /tmp下,那么只要传入/root/a.txt 和 /tmp/a.txt即可,那么关键就是/tmp和a.txt的拼装,在拷贝到/tmp/下你也可以先判断下目标是否有相同文件存在。若存在可以提示用户是否覆盖(这个功能我还没做)。这里主要还是字符串处理函数用的比较多,还有一个就是函数返回值得一个难点(下篇博文介绍下函数返回值)。C++ Primer Plus 第6版 中文版 清晰有书签PDF+源代码 http://www.linuxidc.com/Linux/2014-05/101227.htm读C++ Primer 之构造函数陷阱 http://www.linuxidc.com/Linux/2011-08/40176.htm读C++ Primer 之智能指针 http://www.linuxidc.com/Linux/2011-08/40177.htm读C++ Primer 之句柄类 http://www.linuxidc.com/Linux/2011-08/40175.htm将C语言梳理一下,分布在以下10个章节中:
  1. Linux-C成长之路(一):Linux下C编程概要 http://www.linuxidc.com/Linux/2014-05/101242.htm
  2. Linux-C成长之路(二):基本数据类型 http://www.linuxidc.com/Linux/2014-05/101242p2.htm
  3. Linux-C成长之路(三):基本IO函数操作 http://www.linuxidc.com/Linux/2014-05/101242p3.htm
  4. Linux-C成长之路(四):运算符 http://www.linuxidc.com/Linux/2014-05/101242p4.htm
  5. Linux-C成长之路(五):控制流 http://www.linuxidc.com/Linux/2014-05/101242p5.htm
  6. Linux-C成长之路(六):函数要义 http://www.linuxidc.com/Linux/2014-05/101242p6.htm
  7. Linux-C成长之路(七):数组与指针 http://www.linuxidc.com/Linux/2014-05/101242p7.htm
  8. Linux-C成长之路(八):存储类,动态内存 http://www.linuxidc.com/Linux/2014-05/101242p8.htm
  9. Linux-C成长之路(九):复合数据类型 http://www.linuxidc.com/Linux/2014-05/101242p9.htm
  10. Linux-C成长之路(十):其他高级议题
三:实现
#include<stdio.h>#include<unistd.h>#include<fcntl.h>#include<unistd.h>#include<stdlib.h>#include<sys/types.h>#include<sys/stat.h>#include<string.h>#include<dirent.h>#include <libgen.h>#define BUFFERSIZE 4096#define COPYMODE 0644 char *deal_path(char *,char *);char *deal_path1(char *,struct dirent *);int is_file(char *);char *deal_with(char *,char *);void oops(char *,char *);int exists(char *);void do_cp(char *,char *);int main(int argc,char *argv[]){        char answer[10];        char c;        //设置buf        struct stat filebuf1;        struct stat filebuf2;        struct stat tmpbuf;        char *filename=NULL;        char *filename2=NULL;        struct dirent  *dirname;        DIR *dir_ptr;        //判断参数                if(argc != 3){                fprintf(stderr,"Usage: %s source destination ",*argv);                exit(1);        }        //判断源文件和目标文件是否相等        if(strcmp(argv[1],argv[2]) == 0)        {                fprintf(stderr,"No Copy Source File equal Dest File ");                exit(1);        }        //测试文件是否可以访问         if(access(argv[2],F_OK) == 0){                //询问文件是否可以覆盖                printf("Can you ovver the file (y/n):");                scanf("%9s",&answer);                while((c = getchar()) != EOF && c != " ");        }         //判断用户的输入         if(*answer != "y" && *answer != "Y"){                fprintf(stderr,"the dst file exists,don"t over ");                exit(1);        }         //判断目标是否是目录        stat(argv[2],&filebuf2);        stat(argv[1],&filebuf1);        if(!S_ISDIR(filebuf1.st_mode)){                if(S_ISDIR(filebuf2.st_mode))                        filename = deal_path(argv[2],argv[1]);                else                        filename = argv[2];        //      printf("%s ",filename);                do_cp(argv[1],filename);                free(filename);           }                     else{                if(S_ISDIR(filebuf2.st_mode))                if((dir_ptr = opendir(argv[1])) == NULL)                        sprintf("stderr","Can"t open dir %s ",argv[1]);                else                        while((dirname=readdir(dir_ptr)) != NULL){                                        filename = deal_path(argv[1],dirname->d_name);                                        if(is_file(filename)){                                                filename2 = deal_with(filename,argv[2]);                                                do_cp(filename,filename2);                                                free(filename);                                                free(filename2);                                        }else{                                                free(filename);                                                continue;                                        }                                }                        }                closedir(dir_ptr);        }   void do_cp(char *path1,char *path2){        int in_fd,out_fd,n_chars;        char buf[BUFFERSIZE];        if((in_fd = open(path1,O_RDONLY)) == -1)                oops("Cannot open",path1);        if((out_fd = open(path2,O_WRONLY|O_CREAT,COPYMODE)) == -1)                oops("Cannot create",path2);        //开始读取        while((n_chars = read(in_fd,buf,BUFFERSIZE)) > 0)                if(write(out_fd,buf,n_chars) != n_chars)                oops("Write error to",path2);        //判断最后是否写入        if(n_chars == -1)                oops("Read error from,path1","");                        //判断最后是否写入        if(n_chars == -1)                oops("Read error from,path1","");        //关闭文件        if(close(in_fd) == -1||close(out_fd) == -1)                oops("Error closing files","");}  void oops(char *s1,char *s2){        fprintf(stderr,"Error:%s ",s1);        perror(s2);        exit(1);}  int exists(char *filename){        return access(filename,F_OK); } int is_file(char *filename){        struct stat filebuf;        stat(filename,&filebuf);        if(S_ISREG(filebuf.st_mode))                return 1;        else                return 0;} char *deal_with(char *filename,char *filename2){        char *file=NULL;;        if((file = (char *)malloc(strlen(basename(filename))+strlen(filename2)+3)) == NULL)                perror("malloc error");                        else{                if(filename2[strlen(filename2)-1] == "/"){                        strcpy(file,filename2);                        strcat(file,basename(filename));                }else{                        strcpy(file,filename2);                        strcat(file,"/");                        strcat(file,basename(filename));                   }        }        return file;} char *deal_path(char *file,char *file2){        char *filename=NULL;        if((filename = (char *)malloc(strlen(file)+strlen(file2)+3)) == NULL)                                perror("Malloc erro:");        else{         if(file[strlen(file)-1] == "/"){                        strcpy(filename,file);                        strcat(filename,file2);        }else{                        strcpy(filename,file);                        strcat(filename,"/");                        strcat(filename,file2);                }        }        return filename; }用的最多的还是这个deal_path这个函数,这个函数会判断/tmp/ /tmp这个的区别,最终会将给出的两个参数合并成一个文件路径创建并写入要拷贝的内容。四:总结C语言基础很重要,最近在看C专家编程,C和指针,感触很深里面很多C语言的细节我都不知道。还有linux C编程实战中的关于结构体的字节对齐我也知之甚少。后期会用博客记录相关内容加深自己对这些内容的理解。本文永久更新链接地址:http://www.linuxidc.com/Linux/2014-07/104735.htm