本文是在该文“Linux C++实现拷贝文件夹”的基础上做了一些修改和优化:
- 修改了CopyFile(std::string sourcePath,std::string destPath)函数返回值不匹配的问题;
- 原文代码只支持拷贝文件夹,增加拷贝文件功能.
#include<stdlib.h>
#include<dirent.h>
#include<string.h>
#include<stdio.h>
#include<sys/stat.h>
#include<iostream>
#define BUFFER_LENGTH 8192
// 判断传入的路径是否是目录(不是目录就是文件),目录返回1,文件返回0
int IsDir(std::string path)
{
if(path.empty())
{
return 0;
}
struct stat st;
if(0 != stat(path.c_str(),&st))
{
return 0;
}
if(S_ISDIR(st.st_mode))
{
return 1;
}
else
{
return 0;
}
}
void AddSlash(std::string &sourcePath,std::string &destPath)
{
if((IsDir(sourcePath)) && (sourcePath.back() != '/'))
{
sourcePath += "/";
}
if(destPath.back() != '/')
{
destPath += "/";
}
}
int CreatPath(std::string &sourcePath,std::string &destPath)
{
AddSlash(sourcePath, destPath);
// 处理源路径,如果源路径是目录,执行mkdir创建目标路径,否则先执行mkdir再执行touch创建目标路径
char acBuf[128] = "";
// 先使用opendir()检查目标路径是否存在,不存在再使用mkdir创建
DIR* destPathDir = opendir(destPath.c_str());
if(!destPathDir)
{
// 递归创建目录
sprintf(acBuf, "mkdir -pv %s", destPath.c_str());
system(acBuf);
}
closedir(destPathDir);
if (IsDir(sourcePath)) ///< 如果传入的是目录,创建完目标目录就可以直接返回了
{
return 1;
}
else ///< 传入的如果是文件,则使用touch继续创建
{
// 找到最后一个 '/' 的位置
size_t found = sourcePath.find_last_of("/");
// 截取文件名部分
std::string fileName = sourcePath.substr(found + 1);
destPath = destPath + fileName;
sprintf(acBuf, "touch %s", destPath.c_str());
system(acBuf);
}
return 0;
}
int CopyFile(std::string sourcePath,std::string destPath)
{
int len = 0;
FILE *pIn = NULL;
FILE *pOut = NULL;
char buff[BUFFER_LENGTH] = {0};
if((pIn = fopen(sourcePath.c_str(),"r"))==NULL)
{
printf("Open File %s Failed...\n", sourcePath.c_str());
return 1;
}
if((pOut=fopen(destPath.c_str(),"w"))==NULL)
{
printf("Create Dest File Failed...\n");
return 1;
}
while((len = fread(buff,sizeof(char),sizeof(buff),pIn))>0)
{
fwrite(buff,sizeof(char),len,pOut);
}
fclose(pOut);
fclose(pIn);
}
/********************************************************************************
* @brief 拷贝文件或文件夹
*
* @param sourcePath 源文件or文件夹路径
* @param destPath 目标目录
*
* @return 源文件不存在返回-1,正常执行返回0
*
* @details 当拷贝文件时:
* sourcePath 参数是该文件的绝对路径,如:/home/copyTest/666.txt
* destPath 参数是目标目录,如:/home/copyObj/textFiles/
* 当拷贝文件夹时:
* sourcePath 参数是源目录,如:/home/copyTest/20240524/
* destPath 参数是目标目录,如:/home/copyObj/dateDir/
********************************************************************************/
int CopyFolder(std::string sourcePath,std::string destPath)
{
int nIsDir = IsDir(sourcePath);
// 如果源路径不存在,直接退出
DIR* source=opendir(sourcePath.c_str());
if((nIsDir) && (!source)) ///< 传入的目录不存在,返回-1退出
{
printf("Source Dir Path Is Not Existed\n");
closedir(source);
return -1;
}
closedir(source);
printf("sourcePath1: %s\n", sourcePath.c_str());
printf("destPath1: %s\n", destPath.c_str());
CreatPath(sourcePath, destPath);
printf("sourcePath2: %s\n", sourcePath.c_str());
printf("destPath2: %s\n", destPath.c_str());
if (!nIsDir) ///< 源路径是文件
{
CopyFile(sourcePath,destPath);
printf("Copy From %s To %s Successed\n",sourcePath.c_str(),destPath.c_str());
}
else
{
struct dirent* filename = NULL;
DIR* dp=opendir(sourcePath.c_str());
while(filename=readdir(dp))
{
std::string fileSourcePath = sourcePath;
std::string fileDestPath = destPath;
fileSourcePath += filename->d_name;
fileDestPath += filename->d_name;
if(IsDir(fileSourcePath.c_str())) ///< 判断源路径是目录还是文件,如果是目录执行递归调用,否则执行文件复制操作
{
if(strncmp(filename->d_name, ".", 1) && strncmp(filename->d_name, "..", 2)) ///< 避免处理当前目录和上一级目录
{
CopyFolder(fileSourcePath, fileDestPath);
}
}
else
{
CopyFile(fileSourcePath,fileDestPath);
printf("Copy From %s To %s Successed\n",fileSourcePath.c_str(),fileDestPath.c_str());
}
}
closedir(dp);
}
return 0;
}
int main(int argc,char *argv[])
{
if(argv[1]==NULL||argv[2]==NULL)
{
printf("Please Input Source Path and Destnation Path\n");
return 1;
}
std::string sourcePath=argv[1];//source path
std::string destPath=argv[2];//destination path
CopyFolder(sourcePath,destPath);
return 0;
}
g++ -g copy.cpp -o copy -std=c++11
#bash中测试copy进程
./copy "/home/copyTest/666.txt" "/home/copyObj/textFiles/"