Linux下C++非递归方式实现目录的递归拷贝和删除

最“高效”的实现

Linux下C++可以通过调用系统的system函数来执行shell命令,这无疑是最快的实现方法,话不多说,上代码。

#include <stdlib.h>
#include <string>

void CopyFileAndDirectory(const std::string &_old_path, const std::string &_new_path)
{
    std::string copy_command = "cp -r " + _old_path + " " + _new_path;
    system(copy_command.c_str());
}

void RemoveFileAndDirectory(const std::string &_path)
{
    std::string remove_command = "rm -rf " + _path;
    system(remove_command.c_str());
}

没错,使用shell命令就是这么简单明了。

为什么会重复造轮子

在此之前我并不是很了解C++调用shell的操作,于是使用递归方式实现了一个版本(参见:Linux下C++实现目录的递归拷贝和删除),但是静态检查时MISRA规则要求不能使用递归。于是乎,我又开始思考怎么实现一个非递归的版本。

非递归方式的实现

实现细节在代码中详细注释了,偷了一下懒把两个主要接口的返回值类型都写成void了。

#include <iostream>
#include <vector>
#include <queue>
#include <string>
#include <fstream>
#include <cstdio>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <cstring>

/* Check whether the path identified by 'filename' is a file */
static bool IsFile(const std::string &filename)
{
    struct stat buffer;
    return (stat(filename.c_str(), &buffer) == 0 && S_ISREG(buffer.st_mode));
}

/* Check whether the path identified by 'filefodler' is a fodler */
static bool IsDirectory(const std::string &filefodler)
{
    struct stat buffer;
    return (stat(filefodler.c_str(), &buffer) == 0 && S_ISDIR(buffer.st_mode));
}

/* Copy the file named by old_name to new_name */
int CopyFile(const std::string &old_name, const std::string &new_name)
{
    std::ifstream ifs(old_name, std::ifstream::binary);
    std::ofstream ofs(new_name, std::ifstream::binary | std::ifstream::trunc);
    if (ifs.good() == false)
    {
        return -1;
    }

    ofs << ifs.rdbuf();

    ifs.close();
    ofs.close();
    return 0;
}

/* Copy all files and sub directories in directory to new path */
void CopyFileAndDirectory(const std::string &_old_path, const std::string &_new_path)
{
    DIR *directory_ptr;
    struct dirent *dirent_ptr;

    /* Record the source directory and target directory. */
    std::queue< std::pair<std::string, std::string>> path_queue;
    path_queue.push(std::pair<std::string, std::string>(_old_path, _new_path));

    while (path_queue.size() > 0)
    {
        /* Fetch the first element in the queue. */
        auto path_pair = path_queue.front();
        path_queue.pop();

        /* If the element is a directory */
        if (IsDirectory(path_pair.first))
        {
            /* Judge whether the target directory exists. */
            if (access(path_pair.second.c_str(), 0) == -1)
            {
                /* If the target directory does not exist, create it */
                if (mkdir(path_pair.second.c_str(), 0755) < 0)
                {
                    std::cout << "[CopyFileAndDirectory] mkdir failed , the errno = " << strerror(errno) << std::endl;
                }
            }

            /* Open the source directory */
            if ((directory_ptr = opendir(path_pair.first.c_str())) == NULL)
            {
                std::cout << "open directory failed directory name = " << path_pair.first << std::endl;
            }

            /* Traverse source directory */
            while ((dirent_ptr = readdir(directory_ptr)) != NULL)
            {
                if((strcmp(dirent_ptr->d_name, ".") != 0) && (strcmp(dirent_ptr->d_name, "..") != 0))
                {
                    /* Add the elements under the source directory to the queue. */
                    auto old_file = path_pair.first + "/" + dirent_ptr->d_name;
                    auto new_file = path_pair.second + "/" + dirent_ptr->d_name;
                    path_queue.push(std::pair<std::string, std::string>(old_file, new_file));
                }
            }
            closedir(directory_ptr);
        }
        else if (IsFile(path_pair.first))
        {
            /* If the element is a file, just copy it */
            CopyFile(path_pair.first, path_pair.second);
        }
        else
        {
            /* do nothing */
        }
    }
}


/* Remove all files and sub directories in directory */
void RemoveFileAndDirectory(const std::string &_path)
{
    DIR *directory_ptr;
    struct dirent *dirent_ptr;

    /* Record the directory name that will be removed */
    std::queue<std::string> path_queue;
    std::vector<std::string> path_set;
    path_queue.push(_path);

    
    while(path_queue.size() > 0)
    {
        /* Fetch the first element in the queue. */
        auto path_name = path_queue.front();
        path_queue.pop();

        /* If the element is a directory */
        if(IsDirectory(path_name))
        {
            /* Record the name of the directory and delete it after deleting its child elements. */
            path_set.push_back(path_name);

            /* Open the directory */
            if ((directory_ptr = opendir(path_name.c_str())) == NULL)
            {
                std::cout << "Opendir error: " << strerror(errno) << std::endl;
            }

            /* Traverse the directory */
            while ((dirent_ptr = readdir(directory_ptr)) != NULL)
            {
                if((strcmp(dirent_ptr->d_name, ".") != 0) && (strcmp(dirent_ptr->d_name, "..") != 0))
                {
                    /* Add the elements under the directory which wiil be remove to the queue. */
                    auto item_path = path_name + "/" + dirent_ptr->d_name;
                    path_queue.push(item_path);
                }
            }

            closedir(directory_ptr);
        }
        else if(IsFile(path_name))
        {
            /* If the element is a file, just remove it */
            remove(path_name.c_str());
        }
        else
        {
            /* do nothing */
        }
    }

    /* Remove empty directories */
    while(path_set.size() > 0)
    {
        auto last_item = path_set.back();
        path_set.pop_back();
        auto result = rmdir(last_item.c_str());
        if(result != 0)
        {
            std::cout<< "remove last_item failed = " << last_item << std::endl;
        }
    }
}

int main(void)
{
    std::string old_path = "/WorkSpace/TestPath";
    std::string new_path = "/WorkSpace/NewPath";
    CopyFileAndDirectory(old_path, new_path);
    RemoveFileAndDirectory(new_path);

    return 0;
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值