- A+
项目要求
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("