多线程复制文件夹
pThread复制文件夹
C++通过pthread复制文件夹。主要处理普通文件和链接文件。事实上只要处理好链接文件即可。我们可以通过判断链接的文件是文件夹还是文件即可判断对当前文件是通过文件直接复制还是通过文件夹递归复制。
#include <iostream>
#include <dirent.h>
#include <string>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <vector>
#include <cstring>
#include <fcntl.h>
#include <pthread.h>
using namespace std;
vector<string> files;
vector<string> links;
char* source;
char* destination;
int fileNum, linkNum;
int fileSeg, linkSeg;
int threadNum;
typedef struct {
int threadId;
} threadParm_t;
void copyDirectory(const char *src);
void copyFile(const char *src);
void copySymbolicLink(const char *src);
void addFile(char* filePath) {
string tempPath = filePath;
files.push_back(tempPath);
}
void addLink(char* linkPath) {
string tempPath = linkPath;
links.push_back(tempPath);
}
void *threadCopy(void *parm) {
threadParm_t *p = (threadParm_t *)parm;
int threadId = p->threadId;
int fileStart = threadId * fileSeg;
int fileEnd = (threadId + 1) * fileSeg;
if (threadId == threadNum - 1) {
fileEnd = fileNum;
}
for (int i = fileStart; i < fileEnd; i++) {
copyFile(files[i].c_str());
}
pthread_exit(NULL);
return NULL;
}
int main() {
source="/home/zfl2110414/Downloads/linux-6.6.2";
destination="/home/zfl2110414/Downloads/MultiThreads";
//我们再vector中存取的是相对路径,因此第一遍遍历是特殊情况,需要先把源文件夹的路径加上
DIR* dir;
struct dirent* ptr;
threadNum = 4;
pthread_t thread[threadNum];
threadParm_t threadParm[threadNum];
if(NULL == opendir(destination)) {
mkdir(destination, 0777);
}
printf("threadnum:%d\n", threadNum);
dir = opendir(source);
while((ptr = readdir(dir)) != NULL) {
if (strcmp(ptr -> d_name, ".") == 0 || strcmp(ptr -> d_name, "..") == 0) {
continue;
}
if (ptr -> d_type == DT_DIR) {
copyDirectory(ptr -> d_name);
}
else if (ptr -> d_type == DT_LNK) {
addLink(ptr -> d_name);
}
else {
addFile(ptr -> d_name);
}
}
// 由于处理链接文件时,可能会改变links和files的大小,因此应先处理链接文件
closedir(dir);
for(int i=0;i<links.size();i++){
copySymbolicLink(links[i].c_str());
}
//随着文件的复制,links的大小也会改变,进而完成对所有链接文件的复制
fileNum = files.size();
fileSeg = fileNum / threadNum;
for (int i = 0; i < threadNum; i++) {
threadParm[i].threadId = i;
pthread_create(&thread[i], nullptr, threadCopy, (void*)&threadParm[i]);
}
for (int i = 0; i < threadNum; i++)
pthread_join(thread[i], nullptr);
exit(0);
}
void copyFile(const char *src){
char dest[PATH_MAX];
char source0[PATH_MAX];
sprintf(dest,"%s/%s",destination,src);
sprintf(source0,"%s/%s",source,src);
FILE* fp_source=fopen(source0,"rb");
FILE* fp_dest=fopen(dest,"wb");
if(fp_source==NULL||fp_dest==NULL){
perror("Open file error...");
return;
}
char buf[1024];
int len;
while((len=fread(buf,1,1024,fp_source))>0){
fwrite(buf,1,len,fp_dest);
}
fclose(fp_source);
fclose(fp_dest);
}
void copySymbolicLink(const char *src) {
struct stat link_info,target_info;
// 获取软链接的信息
char source0[PATH_MAX];
char dest[PATH_MAX];
sprintf(source0,"%s/%s",source,src);
sprintf(dest,"%s/%s",destination,src);
if (lstat(source0, &link_info) == -1) {
perror("lstat error...");
return;
}
if(stat(source0,&target_info)==-1){
perror("stat error...");
return;
}
if(S_ISDIR(target_info.st_mode)){
// Handle directory
copyDirectory(src);
}
else{
// Handle regular file
copyFile(src);
}
}
//后续遍历要先进行字符串拼接,然后打开文件夹,再进行遍历
void copyDirectory(const char *src) {
DIR *dir;
struct dirent *ptr;
struct stat buf;
char filepath_source[PATH_MAX];
char filepath_dest[PATH_MAX];
char tempSrc[PATH_MAX];
sprintf(filepath_source, "%s/%s", source, src);
sprintf(filepath_dest, "%s/%s", destination, src);
// linux/input
if ((dir = opendir(filepath_source)) == NULL) {
perror("Open dir error...");
return;
}
mkdir(filepath_dest, 0777);
char filepath_source1[PATH_MAX];
while ((ptr = readdir(dir)) != NULL) {
sprintf(filepath_source1, "%s/%s", filepath_source, ptr->d_name);
if (lstat(filepath_source1, &buf) == -1) {
perror("lstat error...");
continue;
}
strcpy(tempSrc,src);
strcat(tempSrc,"/");
strcat(tempSrc,ptr->d_name);
if (S_ISLNK(buf.st_mode)) {
// Handle symbolic link
addLink(tempSrc);
} else if (S_ISDIR(buf.st_mode)) {
// Handle directory
if (strcmp(ptr->d_name, ".") != 0 && strcmp(ptr->d_name, "..") != 0)
copyDirectory(tempSrc);
} else {
// Handle regular file
addFile(tempSrc);
}
}
closedir(dir);
}
值得一提的是,这里我们复制文件夹要注意,软链接的文件夹复制会导致files和links的大小发生变化,因此我们要先处理软链接,再通过多线程处理普通文件。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现