2011-12-21 154 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

相關問題