以下代码实现目录复制(linux 系统下), 依赖于 pthread 库(第一版本)
代码错误:stat 函数无法获取文件夹大小
应该递归将文件复制放入任务当中
总结,以上代码不仅有错误,而且还没有使用到线程池,思路不清晰。
#include "pthpool.h"
#include <sys/stat.h>
#include <dirent.h>
#include <stdio.h>
// 原始路径
struct dir
{
char scr[255];
char dst[255];
char *name;
thread_pool *pool;
};
// 文件名----绝对路径
struct name
{
char src_name[255];
char dst_name[255];
};
// 字符串拼接
char *linkchar(char *src, char *name)
{
char *ret = calloc(1, 255);
int i, j;
for (i = 0; src[i] != '\0'; i++);
src[i] = '/';
i++;
for (j = 0; name[j] != '\0'; j++)
{
src[i] = name[j];
i++;
}
src[i] = '\0';
strcpy(ret, src);
return ret;
}
// 线程任务,进行文件拷贝,参数文件属性
void *copyreg(void *arg)
{
struct name *copyfile = (struct name *)arg;
// printf("src_path: %s\n", copyfile->src_name);
FILE *fp1 = fopen(copyfile->src_name, "r");
if (fp1 == NULL)
{
perror("打开源文件失败");
exit(1);
}
// printf("dst_path: %s\n", copyfile->dst_name);
FILE *fp2 = fopen(copyfile->dst_name, "w");
if (fp2 == NULL)
{
perror("打开目标文件失败");
exit(1);
}
char *buf = calloc(100, 1);
while(1)
{
long a = ftell(fp1);
if ( ! (fread(buf, 100, 1, fp1)) )
{
long b = ftell(fp1);
fwrite(buf, b-a, 1, fp2);
break;
}
fwrite(buf, 100, 1, fp2);
}
free(buf);
free(copyfile);
fclose(fp1);
fclose(fp2);
return NULL;
}
// 递归获取目录文件名
void mycopy(thread_pool *pool, char *src, char *dst)
{
mkdir(dst, 0777);
DIR *dp = opendir(src);
struct dirent *ep;
char stmp[255];
char dtmp[255];
strcpy(stmp, src);
strcpy(dtmp, dst);
while (1)
{
strcpy(src, stmp);
strcpy(dst, dtmp);
ep = readdir(dp);
if (ep == NULL)
break;
if(ep->d_name[0] == '.')
continue;
src = linkchar(src, ep->d_name);
dst = linkchar(dst, ep->d_name);
struct stat info1;
bzero(&info1, sizeof (info1));
stat(src, &info1);
if (S_ISREG(info1.st_mode))
{
struct name *copy1 = calloc(1, sizeof (struct name));
strcpy(copy1->src_name, src);
strcpy(copy1->dst_name, dst);
add_task(pool, copyreg, copy1);
}
else if (S_ISDIR(info1.st_mode))
{
mycopy(pool, src, dst);
}
}
}
// 获取文件属性
void copydir(thread_pool *pool, char *src, char *dst)
{
struct stat info;
bzero(&info, sizeof (info));
stat(src, &info);
// 复制的本身就是文件
if (S_ISREG(info.st_mode))
{
struct name *copy = calloc(1, sizeof (struct name));
strcpy(copy->src_name, src);
strcpy(copy->dst_name, dst);
add_task(pool, copyreg, copy);
}
// 复制的是目录
else if (S_ISDIR(info.st_mode))
{
mycopy(pool, src, dst);
}
}
// 获取复制路径双方的详细信息
void getdir(struct dir *mydir, char *argv1, char *argv2)
{
bzero(mydir, sizeof (struct dir));
// 判断是绝对路径还是相对路径
if (argv1[0] == '/')
{
strcpy(mydir->scr, argv1);
}
else
{
char scr_path[255]; //源路径
getcwd(scr_path, 255);
char *scr = linkchar(scr_path, argv1);
strcpy(mydir->scr, scr);
//printf("scr_path: %s\n", scr);
}
if (argv2[0] == '/')
{
strcpy(mydir->dst ,argv2);
}
else
{
char dst_path[255]; //目标路径
getcwd(dst_path, 255);
char *dst = linkchar(dst_path, argv2);
strcpy(mydir->dst, dst);
//printf("dst_path: %s\n", dst);
}
}
// 用于主线程计算拷贝目录的时间
void timenum(char *srcname, char *dstname)
{
struct stat srcinfo;
bzero(&srcinfo, sizeof (srcinfo));
stat(srcname, &srcinfo);
printf("from %s to %s\n", srcname, dstname);
struct stat dstinfo;
bzero(&dstinfo, sizeof (dstinfo));
long m = srcinfo.st_size;
printf("src_file size: %ld\n", m);
for (int k = 0; k <= 100; k += 10)
{
printf("%d%c\t", k, '%');
}
printf("\n");
long n;
int i = 0;
int j = 0;
int menu = 0;
int tmp = 0;
if (m != 0)
{
while (1)
{
usleep(10000);
stat(dstname, &dstinfo);
n = dstinfo.st_size*10;
for (menu = 0; menu < (n/m-tmp); menu++)
{
printf(">>>>>>>>");
fflush(stdout);
}
tmp = n/m;
if (tmp == 10)
break;
i++;
}
}
else
{
for(j = 0; j < 10; j++)
{
printf(">>>>>>>>");
fflush(stdout);
}
}
if (i == 0)
i = 1;
printf("\nsuccess...\n");
printf("use time: %dms\n", i*10);
}
int main(int argc, char **argv)
{
printf("begining...\n");
struct dir mydir;
if (argc != 3)
{
printf("use: %s src_filename dis_filename\n", argv[0]);
return 0;
}
getdir(&mydir, argv[1], argv[2]);
// 一、初始化一个带有 20 条线程的线程池
mydir.pool = calloc(1, sizeof (thread_pool));
init_pool(mydir.pool, 20);
char srcname[255];
char dstname[255];
strcpy(srcname, mydir.scr);
strcpy(dstname, mydir.dst);
//二、递归的复制目录
copydir(mydir.pool, mydir.scr, mydir.dst);
// 计时 和 进度条显示
timenum(srcname, dstname);
// 销毁线程池
destroy_pool(mydir.pool);
return 0;
}