2011-12-21 120 views
22

如何使用Boost Filesystem复制目录? 我已经尝试过boost :: filesystem :: copy_directory(),但只创建目标目录并且不复制内容。如何使用Boost Filesystem复制目录

+0

boost :: filesystem :: copy将复制目录或文件。您可以编写一个递归算法,使用该算法复制目录和文件。 – nijansen 2011-12-21 17:55:31

+1

啊。谢谢。我很惊讶,这不是boost :: filesystem的一部分。另外,我在Boost图书馆网站上找不到任何文档,用英文说什么函数copy_directory实际上做了什么。 – Ant 2011-12-22 09:53:39

回答

40
bool copyDir(
    boost::filesystem::path const & source, 
    boost::filesystem::path const & destination 
) 
{ 
    namespace fs = boost::filesystem; 
    try 
    { 
     // Check whether the function call is valid 
     if(
      !fs::exists(source) || 
      !fs::is_directory(source) 
     ) 
     { 
      std::cerr << "Source directory " << source.string() 
       << " does not exist or is not a directory." << '\n' 
      ; 
      return false; 
     } 
     if(fs::exists(destination)) 
     { 
      std::cerr << "Destination directory " << destination.string() 
       << " already exists." << '\n' 
      ; 
      return false; 
     } 
     // Create the destination directory 
     if(!fs::create_directory(destination)) 
     { 
      std::cerr << "Unable to create destination directory" 
       << destination.string() << '\n' 
      ; 
      return false; 
     } 
    } 
    catch(fs::filesystem_error const & e) 
    { 
     std::cerr << e.what() << '\n'; 
     return false; 
    } 
    // Iterate through the source directory 
    for(
     fs::directory_iterator file(source); 
     file != fs::directory_iterator(); ++file 
    ) 
    { 
     try 
     { 
      fs::path current(file->path()); 
      if(fs::is_directory(current)) 
      { 
       // Found directory: Recursion 
       if(
        !copyDir(
         current, 
         destination/current.filename() 
        ) 
       ) 
       { 
        return false; 
       } 
      } 
      else 
      { 
       // Found file: Copy 
       fs::copy_file(
        current, 
        destination/current.filename() 
       ); 
      } 
     } 
     catch(fs::filesystem_error const & e) 
     { 
      std:: cerr << e.what() << '\n'; 
     } 
    } 
    return true; 
} 

用法:

copyDir(boost::filesystem::path("/home/nijansen/test"), boost::filesystem::path("/home/nijansen/test_copy"));(UNIX)

copyDir(boost::filesystem::path("C:\\Users\\nijansen\\test"), boost::filesystem::path("C:\\Users\\nijansen\\test2"));(Windows)中

据我看到的,可能发生的最糟糕的是,什么也没有发生,但我赢了不承诺任何事情!使用风险自负。

请注意,您正在复制到的目录一定不存在。如果您试图复制的目录中的目录无法读取(请考虑权限管理),它们将被跳过,但其他目录仍应被复制。

更新

重构功能各自的意见。此外,该功能现在返回成功结果。如果给定目录或源目录内的任何目录的要求未得到满足,它将返回false,但如果不能复制单个文件,则不会。

+7

如果你使用C++,你应该使用'std :: cerr'而不是'fprintf'和'stderr'。而且,因为这是Boost.Filesystem,所以你应该使用'boost :: path'而不是'std :: string'。 – 2011-12-21 21:48:40

+0

感谢您的建议,我相应地改进了功能。 – nijansen 2011-12-21 22:33:56

+3

请注意,您仍然必须小心您正在复制的内容。如果你运行'copyDir(boost :: filesystem :: path(“。”),boost :: filesystem :: path(“test”))',它会复制自身直到它被终止,因为路径长度超过限制,或者磁盘空间不足。 – nijansen 2011-12-21 23:18:33

6

我认为这个版本是对@ nijansen的回答版本的改进。它还支持源和/或目标目录是相对的。

namespace fs = boost::filesystem; 

void copyDirectoryRecursively(const fs::path& sourceDir, const fs::path& destinationDir) 
{ 
    if (!fs::exists(sourceDir) || !fs::is_directory(sourceDir)) 
    { 
     throw std::runtime_error("Source directory " + sourceDir.string() + " does not exist or is not a directory"); 
    } 
    if (fs::exists(destinationDir)) 
    { 
     throw std::runtime_error("Destination directory " + destinationDir.string() + " already exists"); 
    } 
    if (!fs::create_directory(destinationDir)) 
    { 
     throw std::runtime_error("Cannot create destination directory " + destinationDir.string()); 
    } 

    for (const auto& dirEnt : fs::recursive_directory_iterator{sourceDir}) 
    { 
     const auto& path = dirEnt.path(); 
     auto relativePathStr = path.string(); 
     boost::replace_first(relativePathStr, sourceDir.string(), ""); 
     fs::copy(path, destinationDir/relativePathStr); 
    } 
} 

的主要区别是异常而不是返回值,使用recursive_directory_iteratorboost::replace_first剥离迭代器路径的公共部分,依靠boost::filesystem::copy()做不同的文件类型正确的事(保留符号链接,例如)。

+0

用于偏好布尔返回值的异常。另外,relativePathStr可以使用path.lexically_relative(sourceDir)来计算,它可能比boost :: replace_first更简单。 – Philippe 2017-04-19 19:35:04

2

因为它的文件系统库已经被包含在C++ std中,所以你不需要为该任务提高性能。加入std::filesystem::copy

#include <exception> 
#include <filesystem> 
namespace fs = std::filesystem; 

int main() 
{ 
    fs::path source = "path/to/source/folder"; 
    fs::path target = "path/to/target/folder"; 

    try { 
     fs::copy(source, target, fs::copy_options::recursive); 
    } 
    catch (std::exception& e) { // Not using fs::filesystem_error since std::bad_alloc can throw too. 
     // Handle exception or use error code overload of fs::copy. 
    } 
} 

std::filesystem::copy_options见。

+0

非常感谢Roi。我希望游客注意你的答案。 – Ant 2017-10-20 14:25:53

+0

注意这被添加到C++ 17中的ISO C++中。 – 2018-03-07 13:30:41

相关问题