With C++, is it possible to recursively copy files and directories from one path to another
Considering the following filesystem
src/fileInRoot
src/sub_directory/
src/sub_directory/fileInSubdir
I want to copy
from src
to another directory target
.
I've created a new question since the questions I've found are platform specific and don't include filtering:
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
.
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();
}
}
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:
relative()
substracts the paths and heeds symlinks
(it uses path::lexically_relative()
and weakly_canonical()
)create_directories()
creates a directory for every element of the given path that does not already existcurrent_path()
returns (or changes) the absolute path of the current working directorypath::stem()
returns the filename without the final extensionpath::generic_string()
gives the narrow string with platform independent directory separator /
For production code, I recommend to pull the error handling out of the utility functions. For error handling, std::filesystem
provides two methods:
std::exception
/std::filesystem::filesystem_error
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With