多线程(线程池)拷贝文件

//由于觉得寻常复制速度很慢,所以特地写了一个线程池用来复制文件,多个线程一起复制需要的文件,同时还可以根据类别选择性复制你想要的文件,拥有拷贝进度和进度条,可统计耗时。话不多说,代码走起。

//这是常用的几个头文件
#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));
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值