Come posso copiare una directory usando Boost Filesystem? Ho provato boost :: filesystem :: copy_directory() ma questo crea solo la directory di destinazione e non copia i contenuti.Come posso copiare una directory usando Boost Filesystem
risposta
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;
}
Usage:
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)
Per quanto vedo, il peggio che può succedere è che non succede nulla, ma ho vinto Prometto qualcosa! Utilizzare a proprio rischio.
Si prega di notare che la directory su cui si sta copiando non deve esistere. Se le directory all'interno della directory che stai tentando di copiare non possono essere lette (si pensi alla gestione dei diritti), verranno saltate, ma le altre dovrebbero essere ancora copiate.
Aggiornamento
riscritta la funzione relativa ai commenti. Inoltre, la funzione ora restituisce un risultato positivo. Restituirà false
se i requisiti per le directory specificate o qualsiasi directory all'interno della directory di origine non sono soddisfatti, ma non se un singolo file non può essere copiato.
Se usi C++, dovresti usare 'std :: cerr' invece di' fprintf' e 'stderr'. Inoltre, poiché questo è Boost.Filesystem, dovresti usare 'boost :: path' invece di' std :: string'. –
Grazie per i suggerimenti, ho migliorato la funzione di conseguenza. – nijansen
Nota che devi ancora stare attento a cosa stai copiando dove. Se hai eseguito 'copyDir (boost :: filesystem :: path (". "), Boost :: filesystem :: path (" test "))', si copierà fino a quando non verrà terminato perché la lunghezza del percorso supera il limite, o si esaurisce lo spazio su disco. – nijansen
Vedo questa versione come una versione migliorata della risposta di @ nijansen. Supporta inoltre che le directory di origine e/o destinazione siano relative.
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);
}
}
Le principali differenze sono eccezioni al posto dei valori di ritorno, l'uso di recursive_directory_iterator
e boost::replace_first
per mettere a nudo la parte comune del percorso iteratore, e basandosi su boost::filesystem::copy()
di fare la cosa giusta, con diversi tipi di file (conservando i collegamenti simbolici, per esempio).
+1 per preferire le eccezioni rispetto ai valori di ritorno booleani. Inoltre, relativoPathStr può essere calcolato utilizzando path.lexically_relative (sourceDir), che può essere più semplice da leggere di boost :: replace_first. – Philippe
Non hai più bisogno di boost per quel compito dato che la sua libreria di file system è stata inclusa in std C++ con ad es. l'aggiunta di 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.
}
}
Vedere anche std::filesystem::copy_options
.
Molte grazie, Roi. Spero che i visitatori notino la tua risposta. – Ant
Nota: questo è stato aggiunto a ISO C++ in C++ 17. –
boost :: filesystem :: copy copia le directory oi file allo stesso modo. È possibile scrivere un algoritmo ricorsivo che copia la directory e i file all'interno di quello. – nijansen
Ah. Grazie. Sono sorpreso che questo non fa parte di boost :: filesystem. Inoltre, non sono riuscito a trovare alcuna documentazione nel sito web della libreria Boost che dicesse in inglese cosa fa effettivamente la funzione copy_directory. – Ant