基于linux用线程池实现文件管理

  • A+
所属分类:linux技术
摘要

  用线程池实现一个大文件夹的拷贝,大文件夹嵌套很多小文件;实现复制到指定文件夹的全部文件夹。


项目要求

1.基本

  用线程池实现一个大文件夹的拷贝,大文件夹嵌套很多小文件;实现复制到指定文件夹的全部文件夹。

2.扩充功能

  显示进度条;拷贝耗时统计;类似linux的tree,不能直接用system()与exec()等函数;根据文件类型拷贝;搜索文件;删除文件等。(暂时加了这么一些功能)

 

实现思路

  先完成基本,逐步完成扩展再优化重构代码。

 

实现过程

基本功能

  基于linux,通过线程池实现的。核心就是线程池的三大基本功能--线程例程、添加线程、销毁线程池。由这三个为基础,对项目进行展开。基本功能,即通过递归读取目录,通过strucr dirent *p这个结构体来实现判断文件类型。如果是普通文件,直接在新目录用文件IO的读写实现拷贝功能(包括标准IO、系统IO,还有共享内存也可以实现),拷贝那里用“添加线程”,保证可以多线程实现拷贝;如果是目录文件,就先创建文件夹--mkdir(),再sprintf拼接字符串以及函数的递归实现子级目录的拷贝。

->拷贝代码

void *myregcp(void *myarg) {     struct copypath *mypath=(struct copypath *)myarg;          //系统IO的复制     int fd1,fd2;     fd1=open(mypath->oldpath,O_RDONLY);     fd2=open(mypath->newpath,O_CREAT|O_TRUNC|O_RDWR,0777);     if(fd1==-1)     {         perror("打开1失败n");         return NULL;     }     if(fd2==-1)     {         perror("打开2失败n");         return NULL;     }     char buf[SIZE];     int nread,nwrite;     while(1)     {         bzero(buf,SIZE);         nread=read(fd1,buf,SIZE);         if(nread==0)             break;         cs=cs+nread;         write(fd2,buf,nread);     }     close(fd1);     close(fd2);         return NULL;     }

->递归读取全部目录

int myreaddir(struct copypath *pp,struct threadpool *pool) {     DIR *dirp=opendir(pp->oldpath);     if(dirp==NULL)     {         perror("失败:n");         return -1;     }     struct dirent *p;         while((p=readdir(dirp))!=NULL)     {             if(p->d_type==DT_REG)        //普通文件         {             struct copypath *mypath=malloc(sizeof(struct copypath));             sprintf(mypath->oldpath,"%s/%s",pp->oldpath,p->d_name);             sprintf(mypath->newpath,"%s/%s",pp->newpath,p->d_name);             add_task(myregcp,mypath,pool);    //实现         }         if(p->d_type==DT_DIR)        //文件夹         {                             if(strcmp(p->d_name,".")!=0 && strcmp(p->d_name,"..")!=0)             {                     struct copypath *mydirpath=malloc(sizeof(struct copypath));                 sprintf(mydirpath->oldpath,"%s/%s",pp->oldpath,p->d_name);                 sprintf(mydirpath->newpath,"%s/%s",pp->newpath,p->d_name);                 mkdir(mydirpath->newpath,0777);                 myreaddir(mydirpath,pool);             }         }     }     closedir(dirp);     return 1; }

  这样就大概完成基本功能,用多线程实现大文件夹的拷贝。

扩充功能

->进度条

  定义两个全局变量,一个用于计算总字节数,另一个计算每次复制的字节数,再用一个显示函数实现进度条的显示。这里要注意缓冲区的问题,所以我用了"fflush(NULL)"这个函数,让它每打印一个'|'的时候,就刷新一次缓冲区。计算总的字节数直接递归全部目录,用"struct stat info"这个结构体里面的"info.st_size"累加,即可得到总的字节数;拷贝功能函数里面有个"cs"变量,就是存放拷贝字节数。显示进度条就用简单的判断,加相除实现。因为是显示20个|,所以我乘20

  num=(float)cs;        //正在复制字节数   k=(num/s)*20;    

->耗时

  有三种思路,用clock()、time()、sleep(1)等都可以实现计时,直接在拷贝前和拷贝后加赋值,然后相减,即可。起初自己是用clock()这个函数,但是每次都是三秒。。。然后转到sleep(),让它自己while()累加实现。

->代码实现树

  还是递归的思想,递归如果是普通文件就打印,是目录文件夹就字符串拼接再递归打印子文件夹下的子文件。

void dirtree(char dirpath[],int level) {     int i;     char *dirname=NULL;     int dirlen;     DIR *dp=opendir(dirpath);     if(dp==NULL)     {         perror("失败:n");         return;     }     struct dirent *ep;     while((ep=readdir(dp))!=NULL)     {         if(strncmp(ep->d_name, ".", 1) == 0)             continue;         for(i=0;i<level;i++)         {             printf("|");             printf("     ");         }         printf("|--- ");         printf("33[1;32;40m %s 33[0mn",ep->d_name);         if(ep->d_type==DT_DIR)         {             //当前目录长度             dirlen=strlen(dirpath)+1;             //备份             dirname=(char *)malloc(dirlen);             memset(dirname,0,dirlen);             memcpy(dirname,dirpath,dirlen);                          strcat(dirpath,"/");             strcat(dirpath,ep->d_name);             dirtree(dirpath,level+1);        //递归实现树效果             //恢复之前的目录名             memcpy(dirpath,dirname,dirlen);             free(dirname);                         dirname = NULL;         }     }         closedir(dp); }

->按类型拷贝文件

  也比较简单,另建一个递归读目录的函数,在普通文件加个if条件判断就可以。

  if(strstr(p->d_name,ftype)!=NULL)

->搜索文件

  类似于win的文件检索功能,在输入那个文件下面实现相似文件名的检索,并打印相关路径。也是递归读取目录,核心的改变代码也就一句。用"strstr()"寻找相应的子字符串,打印。

  if(strstr(p->d_name,filename)!=NULL)

->删除文件夹

  删除稍微要注意一下如果文件夹下面还有其他文件,就不能直接用"rmdir"删除文件夹。先用remove()删除文件,之后再删除子文件夹。也是用递归思想实现的。

 

实现效果

  现在还传不了,后期再传吧。

全部代码

 

#include "myhead.h" #define SIZE 1024*1024 long int s=0;    //总字节数 long int cs=0;    //计算每次复制的字节数 int tm=0;        //计时--以秒为单位 int flag;        //结束标志位 /***************************相关结构体的定义******************************/ struct copypath {     char oldpath[256];     char newpath[256];     char target[50]; }; //创建任务链表结构体 struct tasklist {     void *(*taskp)(void *);     void *taskarg;     struct tasklist *next; }; //创建任务链表表头 struct tasklist *myhead; //初始化任务链表 struct tasklist* task_init() {         struct tasklist *mytask=malloc(sizeof(struct tasklist));     mytask->taskp=NULL;     mytask->taskarg=NULL;     mytask->next=NULL;     return mytask; } //创建线程池 struct threadpool {     int threadnum;//统计当前线程数量     pthread_t *threadid;//存放当前线程的ID号     struct tasklist *taskhead;//保存任务链表的头结点     pthread_mutex_t threadmutex;//互斥锁     int tasknum;//统计任务链表中的数量     pthread_cond_t threadcond;//条件变量     bool threadflag;//用于判断线程池是否开启 };  //线程的多任务函数 void *routine(void *arg) {     struct threadpool *pool=(struct threadpool *)arg;     //负责从任务链表的头结点的下一个位置取出任务然后处理     struct tasklist *p;     while(1)     {         //上锁         pthread_mutex_lock(&(pool->threadmutex));         //判断数量是否为0         while(pool->threadflag==true && pool->tasknum==0)         {             //printf("%ld线程阻塞--waitn",pthread_self());             pthread_cond_wait(&(pool->threadcond),&(pool->threadmutex));         }         if(pool->threadflag==false&&pool->tasknum==0)         {             pthread_mutex_unlock(&(pool->threadmutex));             pthread_exit(NULL);         }         //取出节点处理         p=pool->taskhead->next;         pool->taskhead->next=p->next;         p->next=NULL;         //更新任务数量         pool->tasknum--;         //printf("%ld线程正在执行任务n",pthread_self());         //解锁         pthread_mutex_unlock(&(pool->threadmutex));         (p->taskp)(p->taskarg);         free(p);     } } //初始化线程池结构体 struct threadpool *thread_init(int num) {     struct threadpool *mythread=malloc(sizeof(struct threadpool));//申请堆空间     mythread->threadnum=num;     mythread->threadid=malloc(num*sizeof(pthread_t));     //初始化链表的表头     mythread->taskhead=myhead;     //锁初始化     pthread_mutex_init(&(mythread->threadmutex),NULL);     //条件变量初始化     pthread_cond_init(&(mythread->threadcond),NULL);     mythread->tasknum=0;     mythread->threadflag=true;     for(int i=0;i<num;i++)         pthread_create(&(mythread->threadid[i]),NULL,routine,mythread);     return mythread; } //添加任务函数 int add_task(void *(*p)(void *),void *newarg,struct threadpool *pool) {     //找到尾部     struct tasklist *q=pool->taskhead;     while(q->next!=NULL)         q=q->next;     //准备新结点     struct tasklist *newnode=malloc(sizeof(struct tasklist));     newnode->taskp=p;     newnode->taskarg=newarg;     newnode->next=NULL;          //上锁     pthread_mutex_lock(&(pool->threadmutex));     //尾插     q->next=newnode;     //更新任务数量     pool->tasknum++;     pthread_mutex_unlock(&(pool->threadmutex));     //唤醒条件     pthread_cond_signal(&(pool->threadcond));     return 0;     } /***************************************************************************/ //                                功能函数 /***************************************************************************/ //主目录名 void *mycopyname(void *myarg) {     struct copypath *mypath=(struct copypath *)myarg;     char fpath[15];    //求出主目录的名字     char temp[100];     strcpy(temp,mypath->oldpath);     char *p=strtok(temp,"/");     //获取文件名     while(p!=NULL)     {         bzero(fpath,15);         strcpy(fpath,p);         p=strtok(NULL,"/");     }     strcpy(((struct copypath *)myarg)->target,fpath); } //普通文件复制 void *myregcp(void *myarg) {     struct copypath *mypath=(struct copypath *)myarg;          //系统IO的复制     int fd1,fd2;     fd1=open(mypath->oldpath,O_RDONLY);     fd2=open(mypath->newpath,O_CREAT|O_TRUNC|O_RDWR,0777);     if(fd1==-1)     {         perror("打开1失败n");         return NULL;     }     if(fd2==-1)     {         perror("打开2失败n");         return NULL;     }     char buf[SIZE];     int nread,nwrite;     while(1)     {         bzero(buf,SIZE);         nread=read(fd1,buf,SIZE);         //cs=cs+nread;         if(nread==0)             break;         cs=cs+nread;         write(fd2,buf,nread);     }     close(fd1);     close(fd2);         return NULL;     } //遍历读目录 int myreaddir(struct copypath *pp,struct threadpool *pool) {     DIR *dirp=opendir(pp->oldpath);     if(dirp==NULL)     {         perror("失败:n");         return -1;     }     struct dirent *p;         while((p=readdir(dirp))!=NULL)     {             if(p->d_type==DT_REG)        //普通文件         {             struct copypath *mypath=malloc(sizeof(struct copypath));             sprintf(mypath->oldpath,"%s/%s",pp->oldpath,p->d_name);             sprintf(mypath->newpath,"%s/%s",pp->newpath,p->d_name);             add_task(myregcp,mypath,pool);    //实现         }         if(p->d_type==DT_DIR)        //文件夹         {                             if(strcmp(p->d_name,".")!=0 && strcmp(p->d_name,"..")!=0)             {                     struct copypath *mydirpath=malloc(sizeof(struct copypath));                 sprintf(mydirpath->oldpath,"%s/%s",pp->oldpath,p->d_name);                 sprintf(mydirpath->newpath,"%s/%s",pp->newpath,p->d_name);                 mkdir(mydirpath->newpath,0777);                 myreaddir(mydirpath,pool);             }         }     }     closedir(dirp);     return 1; } //递归算字节数 int size_sum(struct copypath *pp) {     DIR *dirp=opendir(pp->oldpath);     if(dirp==NULL)     {         perror("失败:n");         return -1;     }     struct dirent *p;     struct stat info;     while((p=readdir(dirp))!=NULL)     {             if(p->d_type==DT_REG)        //普通文件         {             struct copypath *mypath=malloc(sizeof(struct copypath));             sprintf(mypath->oldpath,"%s/%s",pp->oldpath,p->d_name);             //计算字节数             stat(mypath->oldpath,&info);             s=s+info.st_size;         }         if(p->d_type==DT_DIR)        //文件夹         {                             if(strcmp(p->d_name,".")!=0 && strcmp(p->d_name,"..")!=0)             {                     struct copypath *mydirpath=malloc(sizeof(struct copypath));                 sprintf(mydirpath->oldpath,"%s/%s",pp->oldpath,p->d_name);                 size_sum(mydirpath);             }         }     }     closedir(dirp);     return 1; } //实现进度条 void *pro_bar(void *myarg) {     int i,j=0;     float k,num;     printf("进度:");     while(1)     {         j=k;         num=(float)cs;        //正在复制字节数         k=(num/s)*20;        //         k=(int)k;                 if(k-j>=1)         {             for(i=0;i<k-j;i++)                     {                                 printf("33[1;31;42m | 33[0m");             }             fflush(NULL);         }         usleep(10000);         if(s==cs)         {             printf("33[1;31;42m | 33[0m");             fflush(NULL);             usleep(200);             break;         }                 }     printf("n任务完成n");     return NULL; } //lseep计时 void *my_time(void *myarg) {     while(1)     {         sleep(1);         tm++;         if(s==cs)         {             break;         }     } } //显示选择拷贝类型界面 int showdow() {     int n;     printf("**********************n");     printf(" 请输入你要拷贝的文件 n");     printf("   1.复制全部文件;    n");     printf("   2.选择类型复制;    n");     printf("   3.原目录文件树;    n");     printf("   4.查找某个文件;   n");     printf("   5.删除某个文件.    n");     printf("**********************n");     scanf("%d",&n);     return n; } //递归读取文件类型的字节数 int ftypesize_sum(struct copypath *pp,char *ftype) {     DIR *dirp=opendir(pp->oldpath);     if(dirp==NULL)     {         perror("失败:n");         return -1;     }     struct dirent *p;     struct stat info;     while((p=readdir(dirp))!=NULL)     {             if(p->d_type==DT_REG)        //普通文件         {             if(strstr(p->d_name,ftype)!=NULL)    //文件类型             {                 struct copypath *mypath=malloc(sizeof(struct copypath));                 sprintf(mypath->oldpath,"%s/%s",pp->oldpath,p->d_name);                 //计算字节数                 stat(mypath->oldpath,&info);                 s=s+info.st_size;             }                     }         if(p->d_type==DT_DIR)        //文件夹         {                 if(strcmp(p->d_name,".")!=0 && strcmp(p->d_name,"..")!=0)             {                     struct copypath *mydirpath=malloc(sizeof(struct copypath));                 sprintf(mydirpath->oldpath,"%s/%s",pp->oldpath,p->d_name);                 ftypesize_sum(mydirpath,ftype);             }         }     }     closedir(dirp);     return 1;     } //递归读取文件类型的目录 int myftyper(struct copypath *pp,struct threadpool *pool,char *ftype) {     DIR *dirp=opendir(pp->oldpath);     if(dirp==NULL)     {         perror("失败:n");         return -1;     }     struct dirent *p;     while((p=readdir(dirp))!=NULL)     {             if(p->d_type==DT_REG)        //普通文件         {             if(strstr(p->d_name,ftype)!=NULL)             {                 struct copypath *mypath=malloc(sizeof(struct copypath));                 sprintf(mypath->oldpath,"%s/%s",pp->oldpath,p->d_name);                 sprintf(mypath->newpath,"%s/%s",pp->newpath,p->d_name);                 add_task(myregcp,mypath,pool);    //实现             }         }         if(p->d_type==DT_DIR)        //文件夹         {                             if(strcmp(p->d_name,".")!=0 && strcmp(p->d_name,"..")!=0)             {                     struct copypath *mydirpath=malloc(sizeof(struct copypath));                 sprintf(mydirpath->oldpath,"%s/%s",pp->oldpath,p->d_name);                 sprintf(mydirpath->newpath,"%s/%s",pp->newpath,p->d_name);                 mkdir(mydirpath->newpath,0777);                 myftyper(mydirpath,pool,ftype);             }         }     }     closedir(dirp);     return 1; } //树实现 void dirtree(char dirpath[],int level) {     int i;     char *dirname=NULL;     int dirlen;     DIR *dp=opendir(dirpath);     if(dp==NULL)     {         perror("失败:n");         return;     }     struct dirent *ep;     while((ep=readdir(dp))!=NULL)     {         if(strncmp(ep->d_name, ".", 1) == 0)             continue;         for(i=0;i<level;i++)         {             printf("|");             printf("     ");         }         printf("|--- ");         printf("33[1;32;40m %s 33[0mn",ep->d_name);         if(ep->d_type==DT_DIR)         {             //当前目录长度             dirlen=strlen(dirpath)+1;             //备份             dirname=(char *)malloc(dirlen);             memset(dirname,0,dirlen);             memcpy(dirname,dirpath,dirlen);                          strcat(dirpath,"/");             strcat(dirpath,ep->d_name);             dirtree(dirpath,level+1);        //递归实现树效果             //恢复之前的目录名             memcpy(dirpath,dirname,dirlen);             free(dirname);                         dirname = NULL;         }     }         closedir(dp); }  //递归查找相似文件-查找文件 int sc_file(struct copypath *pp,char *filename) {     DIR *dirp=opendir(pp->oldpath);     if(dirp==NULL)     {         perror("失败:n");         return -1;     }     struct dirent *p;     while((p=readdir(dirp))!=NULL)     {             if(p->d_type==DT_REG)        //普通文件         {             if(strstr(p->d_name,filename)!=NULL)    //文件类型             {                 struct copypath *mypath=malloc(sizeof(struct copypath));                 sprintf(mypath->oldpath,"%s/%s",pp->oldpath,p->d_name);                 printf("已找到文件路径:%sn",mypath->oldpath);                 free(mypath);             }                     }         if(p->d_type==DT_DIR)        //文件夹         {                 if(strcmp(p->d_name,".")!=0 && strcmp(p->d_name,"..")!=0)             {                     if(strstr(p->d_name,filename)!=NULL)    //文件类型                 {                     struct copypath *mypath1=malloc(sizeof(struct copypath));                     sprintf(mypath1->oldpath,"%s/%s",pp->oldpath,p->d_name);                     printf("已找到文件路径:%sn",mypath1->oldpath);                     free(mypath1);                 }                 struct copypath *mydirpath=malloc(sizeof(struct copypath));                 sprintf(mydirpath->oldpath,"%s/%s",pp->oldpath,p->d_name);                 sc_file(mydirpath,filename);             }         }     }     closedir(dirp);     return 1;     } //删除--文件文件夹 int alldet(struct copypath *pp) {     DIR *dirp=opendir(pp->oldpath);     struct dirent *p;     while((p=readdir(dirp))!=NULL)     {             if(p->d_type==DT_REG)        //普通文件         {                         struct copypath *mypath=malloc(sizeof(struct copypath));             sprintf(mypath->oldpath,"%s/%s",pp->oldpath,p->d_name);             remove(mypath->oldpath);                     }         if(p->d_type==DT_DIR)        //文件夹         {                 if(strcmp(p->d_name,".")!=0 && strcmp(p->d_name,"..")!=0)             {                             struct copypath *mydirpath=malloc(sizeof(struct copypath));                 sprintf(mydirpath->oldpath,"%s/%s",pp->oldpath,p->d_name);                 alldet(mydirpath);                 rmdir(mydirpath->oldpath);             }         }     }     closedir(dirp);     rmdir((pp->oldpath));     return 1;     } /***************************************************************************/  /***************************************************************************/ //                                简化主程序 /***************************************************************************/ int simcopy_all(struct threadpool *mypool)    //简化主程序--复制全部 {         tm=s=cs=0;     struct copypath paths;        //新旧路径结构体     printf("请输入源文件n");     scanf("%s",paths.oldpath);     printf("请输入目标文件n");     scanf("%s",paths.newpath);     mycopyname(&paths);     sprintf(paths.newpath,"%s/%s",paths.newpath,paths.target);     mkdir(paths.newpath,0777);     size_sum(&paths);        //计算字节数     usleep(20);     printf("总字节数:%ldn",s);     add_task(my_time,NULL,mypool);     add_task(pro_bar,NULL,mypool);     myreaddir(&paths,mypool); } void simcopy(struct threadpool *mypool)        //简化主程序--按文件类型复制 {     tm=s=cs=0;     char ftype[6];            //文件类型变量     struct copypath paths;             printf("请输入源文件n");     scanf("%s",paths.oldpath);     printf("请输入目标文件n");     scanf("%s",paths.newpath);     mycopyname(&paths);     sprintf(paths.newpath,"%s/%s",paths.newpath,paths.target);     mkdir(paths.newpath,0777);     printf("请输入要复制的文件类型,如.txt等n");         scanf("%s",ftype);     ftypesize_sum(&paths,ftype);             printf("总字节数:%ldn",s);     usleep(20);     add_task(my_time,NULL,mypool);     add_task(pro_bar,NULL,mypool);     myftyper(&paths,mypool,ftype); } void simtree()                                //简化主程序--文件树 {     char direntName[256];     struct copypath paths;     printf("请输入源文件n");     scanf("%s",paths.oldpath);     memset(direntName, 0, sizeof(direntName));     strcat(direntName, paths.oldpath);     printf("%sn",paths.oldpath);     dirtree(direntName, 0); } void myscfile()                                //简化主程序--查找 {         char fname[256];     struct copypath paths;     printf("请输入查找文件夹名n");     scanf("%s",paths.oldpath);     printf("请输入要查找的文件名n");     scanf("%s",fname);     sc_file(&paths,fname);     usleep(10); } void mydel()                                //简化主程序--删除 {     tm=s=cs=0;     char delfile[100];     struct copypath paths;     printf("请输入要删除的文件夹n");     scanf("%s",paths.oldpath);     size_sum(&paths);        //计算字节数     printf("size is: %ldn",s);     alldet(&paths);     usleep(10); } void endshow()                                //简化主程序--结束 {     printf("请输入          n");     printf("    1--继续     n");     printf("    2--退出     n");     scanf("%d",&flag); } /***************************************************************************/ //销毁线程池 int pool_destroy(struct threadpool *pool) {     int i;     //改变标志位,让线程退出死循环     pool->threadflag=false;     //唤醒所有线程     pthread_cond_broadcast(&(pool->threadcond));     //回收所有线程     for(i=0;i<pool->threadnum;i++)     {         pthread_join(pool->threadid[i],NULL);         //printf("%ld线程已被回收n",pool->threadid[i]);     }     return 0; }  int main() {              struct copypath paths;     while(1)     {         flag=0;         system("clear");                         myhead=task_init();            //初始化任务链表的表头                 struct threadpool *mypool=thread_init(10);        //创建并初始化线程池         int ret=showdow();             switch(ret)         {             case 1:                        //拷贝全部                 simcopy_all(mypool);                                 pool_destroy(mypool);    //线程池的销毁                 printf("拷贝花费:%d secondsn",tm);                 break;             case 2:                        //拷贝部分                 simcopy(mypool);                 pool_destroy(mypool);                 printf("拷贝花费:%d secondsn",tm);                 break;             case 3:                        //显示文件树                                 simtree();                 break;             case 4:                        //查找某个文件--显示相似的文件                 myscfile();                 break;             case 5:                        //删除某个文件夹                 mydel();                                 printf("delete donen");                 break;             default:                 break;         }         endshow();                 if(flag==1)             continue;         else if(flag==2)             break;     }     system("clear");     usleep(20);     return 0; }

 

 

有什么建议,欢迎联系。邮箱:2460576606@qq.com