Bootstrap

【Linux】【C++】实现文件夹或文件拷贝(可直接编译运行)

一、 前言

本文是在该文“Linux C++实现拷贝文件夹”的基础上做了一些修改和优化:

  1. 修改了CopyFile(std::string sourcePath,std::string destPath)函数返回值不匹配的问题;
  2. 原文代码只支持拷贝文件夹,增加拷贝文件功能.

二、代码测试环境

编程语言操作系统系统架构控制器
C++ 11Ubuntu 18.04 LTSarm64LCFC EA-B310

三、代码实现

copy.cpp

#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/"
;