Yes, it is possible to copy a complete directory structure using nothing else than std C++ ... beginning with C++17 and its std::filesystem
which includes std::filesystem::copy
.
- Copying all files can be done using
copy_options::recursive
:
// Recursively copies all files and folders from src to target and overwrites existing files in target.
void CopyRecursive(const fs::path& src, const fs::path& target) noexcept
{
try
{
fs::copy(src, target, fs::copy_options::overwrite_existing | fs::copy_options::recursive);
}
catch (std::exception& e)
{
std::cout << e.what();
}
}
- To copy a certain subset of files using a filter,
recursive_directory_iterator
can be utilized:
// Recursively copies those files and folders from src to target which matches
// predicate, and overwrites existing files in target.
void CopyRecursive(const fs::path& src, const fs::path& target,
const std::function<bool(fs::path)>& predicate /* or use template */) noexcept
{
try
{
for (const auto& dirEntry : fs::recursive_directory_iterator(src))
{
const auto& p = dirEntry.path();
if (predicate(p))
{
// Create path in target, if not existing.
const auto relativeSrc = fs::relative(p, src);
const auto targetParentPath = target / relativeSrc.parent_path();
fs::create_directories(targetParentPath);
// Copy to the targetParentPath which we just created.
fs::copy(p, targetParentPath, fs::copy_options::overwrite_existing);
}
}
}
catch (std::exception& e)
{
std::cout << e.what();
}
}
When calling the second method like
#include <filesystem>
#include <iostream>
#include <functional>
namespace fs = std::filesystem;
int main()
{
const auto root = fs::current_path();
const auto src = root / "src";
const auto target = root / "target";
// Copy only those files which contain "Sub" in their stem.
const auto filter = [](const fs::path& p) -> bool
{
return p.stem().generic_string().find("Sub") != std::string::npos;
};
CopyRecursive(src, target, filter);
}
and the given filesystem is in the working directory of the process, then the result is
target/sub_directory/
target/sub_directory/fileInSubdir
You could also pass the copy_options
as parameter to CopyRecursive()
for even more flexibility.
A list of some of the functions from std::filesystem
which were used above:
For production code, I recommend to pull the error handling out of the utility functions. For error handling, std::filesystem
provides two methods:
- exceptions with
std::exception
/std::filesystem::filesystem_error
- and error codes with
std::error_code
.
Also take into consideration, that std::filesystem
might not be available on all platforms
The filesystem library facilities may be unavailable if a hierarchical file system is not accessible to the implementation, or if it does not provide the necessary capabilities. Some features may not be available if they are not supported by the underlying file system (e.g. the FAT filesystem lacks symbolic links and forbids multiple hardlinks). In those cases, errors must be reported.
std::filesystem
in Linux/Windows? (my credo is to never sacrifice code readability based on assumptions or minor performance gains that are uninteresting for the use case, i.e. their impact does not affect user experience) – Kaohsiung