2011-12-21 18 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"));(UNIX)

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

私の知る限り見るように、起こることができる最悪の事態は何も起こらないということですが、私は勝ちました何も約束しない!自己責任。

コピー先のディレクトリは存在してはいけません。コピーしようとしているディレクトリ内のディレクトリを読み取ることができない場合(権利管理と考える)、それらはスキップされますが、他のディレクトリはコピーされます。

更新はコメントに、それぞれの機能をリファクタリング。さらに、この関数は成功結果を返します。指定されたディレクトリまたはソースディレクトリ内のいずれかのディレクトリの要件が満たされていない場合は、falseを返しますが、1つのファイルをコピーできなかった場合は戻りません。

+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に含まれているので、そのタスクのための追加機能はもう必要ありません。 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

+0

これはC++のISO C++ 17に追加されています。 –

関連する問題