namespace std::filesystem {
void copy(const path& from, const path& to); // (1)
void copy(const path& from, const path& to, std::error_code& ec); // (2)
void copy(const path& from, const path& to, copy_options options); // (3)
void copy(const path& from, const path& to, copy_options options,
std::error_code& ec); // (4)
}
概要
ファイル・ディレクトリ・シンボリックリンクをコピーする。
要件
options
は、各グループのオプションが最大ひとつまで設定されていること
効果
- (1) :
return copy(from, to, copy_options::none);
- (2) :
return copy(from, to, copy_options::none, ec);
-
(3), (4) :
-
まず、コピー元のファイル状態
f
とコピー先のファイル状態t
を、以下のように取得する:
file_status f; file_status t; if ((options & copy_options::create_symlinks) != copy_options::none || (options & copy_options::skip_symlinks) != copy_options::none) { f = symlink_status(from); t = symlink_status(to); } else if ((options & copy_options::copy_symlinks) != copy_options::none) { f = symlink_status(from); t = status(to); } else { f = status(from); t = status(to); }
- 以下のいずれかの場合、エラーを報告する。(3)の場合は例外、(4)の場合は
ec
にエラー情報を設定することでエラー報告とする:!exists(f)
equivalent(from, to)
is_other(f) || is_other(t)
is_directory(f) && is_regular_file(t)
- また、それ以外に、ファイルコピー、シンボリックリンクのコピー、ディレクトリ作成などにおいてエラーが報告される可能性がある
- コピー元がシンボリックリンクである場合、
(options & copy_options::skip_symlinks) != copy_options::none
であれば、なにもしないで終了する!exists(t) && (options & copy_options::copy_symlinks) != copy_options::none
であれば、copy_symlink(from, to)
を実行する- いずれの条件にも合致しない場合は、エラーを報告する
- コピー元が通常ファイルである場合、
(options & copy_options::directories_only) != copy_options::none
であれば、なにもしないで終了する(options & copy_options::create_symlinks) != copy_options::none
であれば、コピー元ファイルのシンボリックリンクを、コピー先に作成する(options & copy_options::create_hard_links) != copy_options::none
であれば、コピー元ファイルのハードリンクを、コピー先に作成する- コピー先がディレクトリである場合、
copy_file(from, to/from.filename(), options)
を実行する - いずれの条件にも合致しない場合は、
copy_file(from, to, options)
を実行する
- コピー元がディレクトリであり、
(options & copy_options::create_symlinks) != copy_options::none
である場合、make_error_code(errc::is_a_directory)
と等値なerror_code
オブジェクトをエラーとして報告する -
コピー元がディレクトリであり、
((options & copy_options::recursive) != copy_options::none || options == copy_options::none)
である場合、- コピー先にディレクトリが存在しない場合は、
create_directory(to, from)
を実行する - その後、コピー元ディレクトリの全ての要素を、以下のようにコピーする (
in-recursive-copy
は、copy_options
には含まれないビットマスク要素):
for (const directory_entry& x : directory_iterator(from)) copy(x.path(), to/x.path().filename(), options | copy_options::in-recursive-copy)
- コピー先にディレクトリが存在しない場合は、
-
いずれでもない場合、
- (3) であれば、なにもしない
- (4) であれば
ec.clear()
を呼び出し、エラー情報をクリアする
-
例外
- (1), (3) : ファイルシステムがエラーを報告する場合がある。エラーが発生した場合は、
std::filesystem::filesystem_error
例外を送出する - (2), (4) : OSがファイルコピーの直接のAPIを定義していない場合、この関数の実装として動的なバッファを確保する可能性がある。その際、メモリ確保で例外が発生する可能性がある
例
#include <cassert>
#include <filesystem>
#include <fstream>
namespace fs = std::filesystem;
int main()
{
// 単純なファイルのコピー。
// コピー先にはファイルが存在していない
// (コピー先にファイルが存在していたらエラー)
{
std::ofstream{"regular1.txt"};
// ファイル"regular1.txt"を、"copy1.txt"にコピーする
fs::copy("regular1.txt", "copy1.txt");
assert(fs::exists("regular1.txt"));
assert(fs::exists("copy1.txt"));
}
// ファイルのコピー。
// コピー先にすでにファイルがある場合は、上書きする
{
std::ofstream{"regular2.txt"};
// ファイル"regular2.txt"を、"copy2.txt"にコピーする
fs::copy("regular2.txt", "copy2.txt", fs::copy_options::overwrite_existing);
assert(fs::exists("regular2.txt"));
assert(fs::exists("copy2.txt"));
}
// ファイルのコピーを、シンボリックリンクの作成として行う
{
std::ofstream{"regular3.txt"};
// ファイル"regular3.txt"へのシンボリックリンクとして、"copy3.txt"を作成する
fs::copy("regular3.txt", "copy3.txt", fs::copy_options::create_symlinks);
assert(fs::exists("regular3.txt"));
assert(fs::exists("copy3.txt"));
assert(fs::is_symlink("copy3.txt"));
}
// シンボリックリンクファイルのコピー
{
fs::create_symlink("regular3.txt", "regular4.symlink");
// シンボリックリンクファイル"regular4.symlink"を、"copy4.symlink"にコピーする
fs::copy("regular4.symlink", "copy4.symlink");
assert(fs::exists("regular4.symlink"));
assert(fs::exists("copy4.symlink"));
}
// ディレクトリのコピー
{
fs::create_directory("dir");
fs::create_directory("dir/sub_dir");
std::ofstream{"dir/a.txt"};
std::ofstream{"dir/sub_dir/b.txt"};
fs::copy("dir", "copy_dir", fs::copy_options::recursive);
assert(fs::exists("copy_dir"));
assert(fs::exists("copy_dir/sub_dir"));
assert(fs::exists("copy_dir/a.txt"));
assert(fs::exists("copy_dir/sub_dir/b.txt"));
}
}
出力
バージョン
言語
- C++17
処理系
- Clang: 7.0 ✅
- GCC: 8.1 ✅
- Visual C++:
参照
- LWG Issue 3015.
copy_options::unspecified
underspecified - LWG Issue 2682.
filesystem::copy()
won't create a symlink to a directory- C++17策定同時の仕様では、
copy("/", "root", copy_options::create_symlinks);
のような状況 (コピー元がディレクトリで、create_symlinks
オプション付き) でコピー先ディレクトリにシンボリックリンクが作られない問題があった。GNUのcp -s
コマンドでは「ディレクトリ"/"
の処理は省略された」と表示されてエラー終了する。この問題に対する仕様変更ではその動作に合わせて、コピー元がディレクトリでcreate_symlinks
オプションが指定された場合、エラーを報告するようになった - この問題は2016年4月に報告された。仕様としてはC++20に含まれるが、過去に遡ってC++17のコンパイラでもこの仕様に対応している可能性がある
- C++17策定同時の仕様では、
- LWG Issue 3013.
(recursive_)directory_iterator
construction and traversal should not benoexcept