基于linux下的线程池复制多级目录及文件
2017-08-18 20:15
288 查看
1. 设计目标
拷贝指定文件夹下的所有子文件夹和文件,利用多线程加快拷贝速度。2.设计方案
./xxx /源文件夹 /目标文件夹递归遍历文件夹下所有文件,为文件夹便创建,为文件便复制
总是先创建文件夹,再复制文件,将复制文件投入线程池任务列队
3.系统框架
4.源码分析
4.1 线程池接口函数
#define MAX_WAITING_TASKS 20000 #define MAX_ACTIVE_THREADS 20 struct task { void *(*do_task)(void *arg); void *arg; struct task *next; }; typedef struct thread_pool { //互斥量和条件变量 pthread_mutex_t lock; pthread_cond_t cond; //停止标志位 bool shutdown; //任务链表 struct task *task_list; //线程号数组 pthread_t *tids; unsigned max_waiting_tasks; unsigned waiting_tasks; unsigned active_threads; }thread_pool; //线程池初始化 threads_number->初始线程数 bool init_pool(thread_pool *pool, unsigned int threads_number); //添加任务进线程池 do_task->功能函数(实际使用只需将此函数改为自己需要的功能函数即可) bool add_task(thread_pool *pool, void *(*do_task)(void *arg), void *arg); //添加线程 int add_thread(thread_pool *pool, unsigned int additional_threads_number); //移除线程 int remove_thread(thread_pool *pool, unsigned int removing_threads_number); //销毁线程池 bool destroy_pool(thread_pool *pool); void *routine(void *arg);
4.2文件操作函数框架
#define SIZE 512 char filecwd[SIZE]; char dircwd[SIZE]; //定义文件的结构体 struct filepath { char filesp[SIZE]; char filedp[SIZE]; }; void rootdir(char sp[SIZE],char dp[SIZE]); void printdir(char *dir,char sp[SIZE],char dp[SIZE],thread_pool *pool); void replace_string(char * source_str,char * targ_str,char *val); void mk_dir(char dpath[]); void* copy_file(void *arg); #endif
4.3遍历目录函数
void printdir(char *dir,char sp[SIZE],char dp[SIZE],thread_pool *pool) { //打开目录指针 DIR *Dp; //文件目录结构体 struct dirent *enty; //详细文件信息结构体 struct stat statbuf; //打开指定的目录,获得目录指针 if(NULL == (Dp = opendir(dir))) { fprintf(stderr,"can not open dir:%s\n",dir); return; } //切换到这个目录 chdir(dir); //遍历这个目录下的所有文件 while(NULL != (enty = readdir(Dp) )) { //通过文件名,得到详细文件信息 lstat(enty->d_name,&statbuf); //判断是不是目录 if(S_ISDIR(statbuf.st_mode)) { if(0 == strcmp(".",enty->d_name) || 0 == strcmp("..",enty->d_name)) //当前目录和上一目录过滤掉 { continue; } getcwd(dircwd,SIZE); strcat(dircwd,"/"); strcat(dircwd,enty->d_name); //工作路径+目录名 replace_string(dircwd,sp,rindex(sp,'/')); char dirdp[SIZE]; sprintf(dirdp,"%s%s",dp,dircwd); //目录最终绝对路径 mk_dir(dirdp); //创建目录 //递归调用 printdir(enty->d_name,sp,dp,pool); } else { struct filepath fpath; //定义文件路径结构体 char temp_path[SIZE]; getcwd(filecwd,SIZE); sprintf(fpath.filesp,"%s/%s",filecwd,enty->d_name); //源文件绝对路径 strcpy(temp_path,fpath.filesp); //暂存源文件绝对路径 replace_string(temp_path,sp,rindex(sp,'/')); sprintf(fpath.filedp,"%s%s",dp,temp_path); //目标文件绝对路径 add_task(pool, copy_file, (void *)(&fpath)); //添加复制文件任务 usleep(9000); //线程休息时间 } } //切换到上一及目录 chdir(".."); //关闭文件指针 closedir(Dp); } /* 据说线程池的线程也需要一定时间休息, 因而我在实际操作中在添加任务add_task()后加了休眠函数usleep(), 否则会导致遗漏任务,休眠的时间根据自己执行的功能函数时间而具体决定 */
/*将字符串中指定子字符串用指定字符串代替,targ_str 是被替换的,val是替换的字符串*/ void replace_string(char * source_str,char * targ_str,char *val) { char temp_sstr[SIZE],result[SIZE]; char *p=NULL,*q=NULL; int len=0; memset(result,0,sizeof(result)); memset(temp_sstr,0,sizeof(temp_sstr)); strcpy(temp_sstr,source_str); p=temp_sstr; q=temp_sstr; len=strlen(targ_str); while(q!=NULL) { if((q=strstr(p,targ_str))!=NULL) { strncat(result,p,q-p); strcat(result,val); strcat(result,"\0"); q+=len; p=q; } else strcat(result,p); } strcpy(source_str,result); }
4.4创建目录及复制文件函数
//创建目录函数 void mk_dir(char dpath[]) { mkdir(dpath,S_IRWXU|S_IRGRP|S_IROTH); } //复制文件函数 void* copy_file(void *arg) { struct filepath *p = (struct filepath *)arg; //转换 FILE *fb_from,*fb_to; int rd_cnt; char rd_buf[1024]; char path1[SIZE]; char dp1[SIZE]; fb_from = fopen(p->filesp,"r"); if(fb_from == NULL) { printf("read open file failure:%s \n",p->filesp); return NULL; } fb_to = fopen(p->filedp,"w+"); if(fb_to == NULL) { printf("write open file failure: %s \n",p->filedp); return NULL; } while((rd_cnt = fread(rd_buf,sizeof(char),1024,fb_from)) > 0) { fwrite(rd_buf,sizeof(char),rd_cnt,fb_to); fflush(fb_to); } i++; printf("%d copy success : %s\n",i,p->filedp); fclose(fb_from); fclose(fb_to); return NULL; }
void rootdir(char sp[SIZE],char dp[SIZE]) { mkdir(dp,S_IRWXU|S_IRGRP|S_IROTH); //创建目标根目录 char dp1[SIZE]; strcpy(dp1,dp); strcat(dp1,rindex(sp,'/')); mkdir(dp1,S_IRWXU|S_IRGRP|S_IROTH); //创建源根目录 }
4.5main函数
#include "thread_pool.h" #include "file.h" int main(int argc,char *argv[]) { if(argc < 3) { printf("path error\n"); return -1; } thread_pool *pool = malloc(sizeof(thread_pool)); //线程池初始化 init_pool(pool, 15); rootdir(argv[1],argv[2]); printdir(argv[1],argv[1],argv[2],pool); destroy_pool(pool); return 0; }
5.最终效果
6.心得笔录
这个小程序主要是靠文件夹递归查找文件为核心实现的,局限在于只能识别目录与一般文件,对管道等文件类型无法识别;对线程池的理解还不够深,对互锁和条件变量使用不够清楚;
出现过复制丢失文件的情况,原因应该为添加任务后的休息时间,太短容易造成丢失,原因还需研究。
先这样了…加油
2017.8.18 bade
相关文章推荐
- Ubuntu_Linux命令:cp (copy)复制文件或目录
- Linux 文件和目录管理之列出、删除、复制、移动及改名
- linux scp 无密码复制文件和目录
- linux下快速删除目录下大量小文件及快速复制大量小文件方法
- Linux命令:cp (copy)复制文件或目录
- Linux 中复制文件到多个目录中
- Linux 文件和目录管理之列出、删除、复制、移动及改名
- 使用scp在linux主机之间复制文件目录
- linux中cp 命令使用介绍(复制文件或者目录)
- Linux 文件和目录管理之列出、删除、复制、移动及改名
- 嵌套删除多级目录, 删除单级目录, 创建多级目录, 复制文件
- Linux机器之间复制文件和目录方式&Linux的scp命令详解
- linux 复制目录中含有隐藏文件和链接如何处理
- linux 复制目录结构,但不复制文件
- Linux命令之目录切换、创建/删除/复制/移动文件 - cd,mkdir,cp,mv,rmdir,rm
- linux复制指定目录下的全部文件到另一个目录中,linux cp 文件夹
- Linux命令:cp (copy)复制文件或目录
- Linux下如何使用cp命令复制文件及复制目录
- scp在Linux中复制文件/目录
- linux中cp (copy)复制文件或目录的用法