Wie kann ich ein Verzeichnis mit Boost Filesystem kopieren? Ich habe versucht, boost :: filesystem :: copy_directory (), aber das erstellt nur das Zielverzeichnis und kopiert nicht den Inhalt.
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;
}
Verwendungszweck:
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)
Das Schlimmste, was passieren kann, ist, dass nichts passiert, aber ich verspreche nichts! Benutzung auf eigene Gefahr.
Bitte beachten Sie, dass das Verzeichnis, in das Sie kopieren, nicht existieren darf. Wenn Verzeichnisse in dem Verzeichnis, das Sie kopieren möchten, nicht gelesen werden können (think rights management), werden sie übersprungen, die anderen sollten jedoch weiterhin kopiert werden.
Update
Funktion entsprechend den Kommentaren überarbeitet. Außerdem liefert die Funktion jetzt ein Erfolgsergebnis. Es wird false
zurückgegeben, wenn die Anforderungen für die angegebenen Verzeichnisse oder ein beliebiges Verzeichnis im Quellverzeichnis nicht erfüllt sind, jedoch nicht, wenn eine einzelne Datei nicht kopiert werden konnte.
Seit C++ 17 brauchen Sie für diese Operation keinen Boost mehr, da das Dateisystem zum Standard hinzugefügt wurde.
Benutze 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.
}
}
Siehe auch std::filesystem::copy_options
.
Ich sehe diese Version als eine verbesserte Version von @ nijansens Antwort. Es wird auch unterstützt, dass die Quell- und/oder Zielverzeichnisse relativ sind.
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);
}
}
Die Hauptunterschiede sind Ausnahmen anstelle von Rückgabewerten, die Verwendung von recursive_directory_iterator
und boost::replace_first
, um den gemeinsamen Teil des Iteratorpfads zu entfernen, und das Verlassen auf boost::filesystem::copy()
, um mit verschiedenen Dateitypen das Richtige zu tun (z. B. Beibehalten von Symlinks).
Dies ist eine Nicht-Boost-Version, die ich basierend auf Doineanns Code verwende. Ich verwende std :: filesystem, konnte aber keine einfache fs::copy(src, dst, fs::copy_options::recursive);
verwenden, da ich filtern wollte, welche Dateien durch die Dateierweiterung in der Schleife kopiert werden.
void CopyRecursive(fs::path src, fs::path dst)
{
//Loop through all the dirs
for (auto dir : fs::recursive_directory_iterator(src))
{
//copy the path's string to store relative path string
std::wstring relstr = dir.path().wstring();
//remove the substring matching the src path
//this leaves only the relative path
relstr.erase(0, std::wstring(src).size());
//combine the destination root path with relative path
fs::path newFullPath = dst / relstr;
//Create dir if it's a dir
if (fs::is_directory(newFullPath))
{
fs::create_directory(newFullPath);
}
//copy the files
fs::copy(dir.path(), newFullPath, fs::copy_options::recursive | fs::copy_options::overwrite_existing);
}
}
relstr.erase(0, std::wstring(src).size());
ist ein funktionsfähiger Boost-weniger-Ersatz für den in der anderen Antwort verwendeten Aufruf boost :: replace_first ()