2011-12-21 3 views
22

부스트 파일 시스템을 사용하여 디렉토리를 복사하려면 어떻게해야합니까? 나는 boost :: filesystem :: copy_directory()를 시도했으나 대상 디렉토리 만 생성하고 내용은 복사하지 않는다.부스트 파일 시스템을 사용하여 디렉토리를 복사하는 방법

+0

boost :: filesystem :: copy는 디렉토리 나 파일을 모두 복사합니다. 디렉토리 및 파일을 복사하는 재귀 알고리즘을 작성할 수 있습니다. – nijansen

+1

아. 고맙습니다. 나는 이것이 boost :: filesystem의 일부가 아니라는 사실에 놀랐다. 또한 Boost 라이브러리 웹 사이트에서 copy_directory 함수가 실제로하는 것을 영어로 말한 문서를 찾을 수 없었습니다. – Ant

답변

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")); (유닉스)

copyDir(boost::filesystem::path("C:\\Users\\nijansen\\test"), boost::filesystem::path("C:\\Users\\nijansen\\test2")); (윈도우)

지금까지 내가 보는 바와 같이, 일어날 수있는 최악은 아무 일도 없다는 것입니다,하지만 난 원 아무것도 약속 하지마! 자신의 책임하에 사용하십시오.

복사 할 디렉토리가 존재하지 않아야합니다. 복사하려는 디렉토리 내의 디렉토리를 읽을 수 없다면 (권한 관리라고 생각하면) 건너 뜁니다. 다른 디렉토리는 계속 복사해야합니다.

업데이트는 의견에 각각의 기능을 리팩토링. 또한이 함수는 이제 성공 결과를 반환합니다. 지정된 디렉토리 또는 소스 디렉토리 내의 디렉토리에 대한 요구 사항이 충족되지 않으면 단일 파일을 복사 할 수없는 경우가 아니라 false을 리턴합니다.

+7

C++을 사용한다면'fprintf'와'stderr' 대신'std :: cerr'을 사용해야합니다. 또한 Boost.Filesystem이기 때문에'std :: string' 대신에'boost :: path'를 사용해야합니다. –

+0

제안에 감사드립니다, 그에 따라 기능을 향상 시켰습니다. – nijansen

+3

여전히 복사하려는 것을주의해야합니다. 'copyDir (boost :: filesystem :: path ("."), boost :: filesystem :: path ("test"))'를 실행하면 경로 길이가 한계를 초과하기 때문에 종료 될 때까지 스스로 복사하고, 또는 디스크 공간이 부족합니다. – nijansen

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

+1은 부울 반환 값보다 예외를 선호합니다. 또한 relativePathStr은 path.lexically_relative (sourceDir)를 사용하여 계산할 수 있으며 boost :: replace_first보다 읽기 쉽습니다. – Philippe

2

파일 시스템 라이브러리가 C++ 표준에 포함되었으므로이 작업을 더 이상 수행 할 필요가 없습니다. 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

많은 감사합니다. 방문자가 당신의 대답을 알기를 바랍니다. – Ant

+0

참고 이것은 C++ 17의 ISO C++에 추가되었습니다. –

관련 문제