//由于觉得寻常复制速度很慢,所以特地写了一个线程池用来复制文件,多个线程一起复制需要的文件,同时还可以根据类别选择性复制你想要的文件,拥有拷贝进度和进度条,可统计耗时。话不多说,代码走起。
//这是常用的几个头文件
#ifndef MYIOHEAD_H_
#define MYIOHEAD_H_
#include <time.h>
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <strings.h>
#include <stdbool.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <dirent.h>
#include <linux/input.h>
// #include "kernel_list.h"
#include <termio.h>
#include <bits/signum.h>
#include <signal.h>
#include <semaphore.h>
#endif
接下来是主代码:
复制完成后会统计出总共复制了多少文件。
#include "myiohead.h"
int count = 0;
int flag = 0;
int dirnum = 1;
int filenum = 0;
char a[1000] = {0};
char mycopypath[100] = {0};//用来保存源目录
char mydirpath[100] = {0};//用来保存目标目录
//把str字符串中的oldstr字符串替换成newstr字符串
char *strrpc(char *str,char *oldstr,char *newstr)
{
char bstr[strlen(str)];//转换缓冲区
memset(bstr,0,sizeof(bstr));
for(int i = 0;i < strlen(str);i++)
{
if(!strncmp(str+i,oldstr,strlen(oldstr)))
{//查找目标字符串
strcat(bstr,newstr);
i += strlen(oldstr) - 1;
}
else
{
strncat(bstr,str + i,1);//保存一字节进缓冲区
}
}
strcpy(str,bstr);
return str;
}
//读取目录数目
int dir_num(char *mydir)
{
char allpath[1000];//保存读取到的文件的路径名
char otherpath[1000];//保存目录中的目录的路径
char * dirpath = mydir;//将传进来的源目录路径名存到dirpath 中
DIR * dir = opendir(dirpath);//打开源目录
if (NULL == dir)
{
perror("打开目录失败!");
exit(0);
}
struct dirent * rd = NULL;
static int mystatic = -1;
mystatic++;
while((rd = readdir(dir)) != NULL) //循环读取目录
{
if(strncmp(rd->d_name,".",1)==0)//跳过当前目录(.)和上一级目录(..)
continue;
//printf("d_name : %s\n", rd->d_name);
// int a = mystatic;
if (rd->d_type == DT_REG)
{
// 获得文件的绝对路径
bzero(allpath,1000);
sprintf(allpath,"%s/%s",dirpath,rd->d_name);
// printf("当前读取的文件名字是:%s\n",allpath);
filenum++;
//printf("这是普通文件!\n");
}
if (rd->d_type == DT_DIR)
{
bzero(otherpath,1000);
sprintf(otherpath,"%s/%s",dirpath,rd->d_name);//保存目录中的目录的路径
dirnum++;
//递归调用自己,接着读取子目录
dir_num(otherpath);
// printf("这是目录!\n");
}
}
return 0;
}
//定义一个结构体表示任务链表
struct tasklist
{
void *(*taskp)(void *);
void *taskarg;
struct tasklist *next;
};
//定义一个结构体表示线程池
struct threadpool
{
int threadnum; //统计目前线程池中线程的数量
pthread_t *threadid; //保存线程的id号
struct tasklist *taskhead; //保存任务链表的头结点
pthread_mutex_t threadmutex; //互斥锁
pthread_cond_t threadcond; //条件变量
int tasknum; //统计任务链表中的任务数量
bool threadflag; //线程池的开关 true--》线程池运行 false--》关闭线程池
};
//读取目录,拷贝整个文件夹
void * read_dir(void *mydir)
{
char allpath[1000];//保存读取到的文件的路径名
char otherpath[1000];//保存目录中的目录的路径
char * dirpath = (char *)mydir;
char copypath[100] = {0}; //创建一个数组保存目标目录路径名
strcpy(copypath,dirpath);
strrpc(copypath,mydirpath,mycopypath);//举例:将/mnt/hgfs/share/改成需要的/hmoe/unbunt/名字存到copypath中
if(access(copypath, F_OK) != 0)//如果目标目录不存在就创建该目标目录
{
mkdir(copypath,0777);
}
DIR * dir = opendir(dirpath);//打开源目录
if (NULL == dir)
{
perror("打开目录失败!");
exit(0);
}
struct dirent * rd = NULL;
while((rd = readdir(dir)) != NULL) //循环读取目录
{
if(strncmp(rd->d_name,".",1)==0)
continue;
//printf("d_name : %s\n", rd->d_name);
if (rd->d_type == DT_REG)
{
//获得文件的绝对路径
bzero(allpath,1000);
sprintf(allpath,"%s/%s",dirpath,rd->d_name);
//printf("当前读取的文件名字是:%s\n",allpath);
int fd1 = open(allpath,O_RDONLY);
if (-1 == fd1)
{
perror("打开源文件失败");
//exit(0);
}
char newpathname[100];
bzero(newpathname,100);
strcat(newpathname,copypath);
strcat(newpathname,rd->d_name);
int fd2 = open(newpathname,O_WRONLY|O_CREAT|O_TRUNC, 0644);
if (-1 == fd2)
{
perror("打开目标文件失败");
//exit(0);
}
char * buf = calloc(1,1000);
while(1)
{
bzero(buf,1000);
int n = read(fd1,buf,1000);
if (n == 0)
{
// printf("*");
count++;
if (count <1000)
{
a[count-1] = '|';
}
printf("\r进度【%s】:%d/%d\r",a,count,filenum);//覆盖打印当前进度和进度条
fflush(stdout); //清空缓冲区
break;
}
if (-1 == n)
{
perror("读取源文件内容失败");
break;
}
//char * tmp = buf;
//while (n>0)
//{
//int m = write(fd2,tmp,n);
//n -= m;
//tmp += m;
//}
int m = write(fd2,buf,n);
}
bzero(newpathname,100);
//把.c文件拷贝到myc目录中
if (strstr(allpath,".c") != 0)
{
char cpc[100];
bzero(cpc,100);
strcpy(cpc,"cp ");
strcat(cpc,allpath);
strcat(cpc," /home/fhq/mytask/myc/");
// strcat(cpc,rd->d_name);
flag++;
system(cpc);
}
close(fd1);
close(fd2);
free(buf);
//printf("这是普通文件!\n");
// if (strstr(rd->d_name,".bmp") != 0)
// {
// insert_(rd->d_name,head);
// }
}
if (rd->d_type == DT_DIR)
{
//递归调用自己,接着读取子目录
bzero(otherpath,1000);
sprintf(otherpath,"%s/%s/",dirpath,rd->d_name);
read_dir(otherpath);
// printf("这是目录!\n");
}
}
/*printf("\n");
printf("复制中,一共复制了%d份文件\n",count );*/
return 0;
}
struct tasklist *myhead;
//线程的任务函数 --》多个线程共用一个任务函数
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阻塞在wait!\n",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--;
//解锁
pthread_mutex_unlock(&(pool->threadmutex));
(p->taskp)(p->taskarg); //处理取出来的任务
free(p);
}
}
//线程池的初始化
struct threadpool *pool_init(int num)
{
int i;
struct threadpool *pool=malloc(sizeof(struct threadpool));
pool->threadnum=num;
pool->threadid=malloc(num*sizeof(pthread_t));
//任务链表的头结点
pool->taskhead=myhead;
//锁初始化
pthread_mutex_init(&(pool->threadmutex),NULL);
//条件变量
pthread_cond_init(&(pool->threadcond),NULL);
pool->tasknum=0;
pool->threadflag=true;
for(i=0; i<num; i++)
pthread_create(&(pool->threadid[i]),NULL,routine,pool);
//threadid[i] *(threadid+i)
return pool;
}
//初始化任务链表的头结点
struct tasklist *task_init()
{
struct tasklist *head=malloc(sizeof(struct tasklist));
head->taskp=NULL;
head->taskarg=NULL;
head->next=NULL;
return head;
}
//添加任务的函数
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;
}
//线程池的销毁,回收所有的线程
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("\n复制完毕,一共复制了大目录中%d份文件\n", count);
printf("复制完毕,一共复制了大目录中%d份c文件到myc中\n", flag);
return 0;
}
int main(int argc, char *argv[])
{
//获得刚进入此处的时间
int seconds1 = time((time_t*)NULL);
if (argc != 3)
{
perror("用法错误,正确用法:./a.out 源目录名 目标目录名");
exit(0);
}
strcpy(mydirpath,argv[1]);
strcpy(mycopypath,argv[2]);
dir_num(argv[1]);
if (filenum <1000)
{
for(int i=0;i<filenum;i++)
{
a[i] =' '; //显示空格
}
}
else if (filenum >= 1000)
{
for(int i=0;i<1000;i++)
{
a[i] =' '; //显示空格
}
}
//准备链表的表头
myhead=task_init();
//初始化线程池
struct threadpool *mypool=pool_init(10);
//添加任务到链表中给线程池中的10个线程去处理
add_task(read_dir,argv[1],mypool);
//线程池的销毁
pool_destroy(mypool);
//获得结束的时间
int seconds2 = time((time_t*)NULL);
printf("复制所有文件一共花了%d秒\n",(seconds2-seconds1));
}