2011-12-21 15 views
22

¿Cómo puedo copiar un directorio usando Boost Filesystem? He intentado boost :: filesystem :: copy_directory() pero eso solo crea el directorio de destino y no copia los contenidos.¿Cómo puedo copiar un directorio usando Boost Filesystem

+0

boost :: filesystem :: copy copiará directorios o archivos por igual. Puede escribir un algoritmo recursivo que copie el directorio y los archivos dentro usando eso. – nijansen

+1

Ah. Gracias. Me sorprende que esto no forme parte de boost :: filesystem. Además, no pude encontrar ninguna documentación en el sitio web de la biblioteca de Boost que dijera en inglés qué hace realmente la función copy_directory. – Ant

Respuesta

40
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; 
} 

Uso:

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)

Por lo que veo, lo peor que puede pasar es que no pasa nada, pero me ganaron ¡Prometo algo! Úselo bajo su propio riesgo.

Tenga en cuenta que el directorio en el que está copiando no debe existir. Si los directorios dentro del directorio que está tratando de copiar no se pueden leer (pensar en la administración de derechos), se omitirán, pero los demás aún se deben copiar.

actualización

refactorizado la función correspondiente a los comentarios. Además, la función ahora devuelve un resultado exitoso. Devolverá false si no se cumplen los requisitos para los directorios especificados o cualquier directorio dentro del directorio de origen, pero no si no se pudo copiar un solo archivo.

+7

Si usa C++ usted, debería usar 'std :: cerr' en lugar de' fprintf' y 'stderr'. Y también, dado que esto es Boost.Filesystem, debería usar 'boost :: path' en lugar de' std :: string'. –

+0

Gracias por las sugerencias, mejoré la función en consecuencia. – nijansen

+3

Tenga en cuenta que todavía debe tener cuidado con lo que está copiando. Si ejecutó 'copyDir (boost :: filesystem :: path (". "), Boost :: filesystem :: path (" test "))', se copiará hasta que finalice porque la longitud de la ruta excede el límite, o te quedas sin espacio en el disco. – nijansen

6

Veo esta versión como una versión mejorada de @ nijansen. También admite que los directorios de origen y/o destino sean relativos.

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); 
    } 
} 

Las principales diferencias son excepciones en lugar de los valores de retorno, el uso de recursive_directory_iterator y boost::replace_first para despojar a la parte constante de la ruta iterador, y confiando en boost::filesystem::copy() hacer lo correcto con diferentes tipos de archivos (preservando los enlaces simbólicos, por ejemplo).

+0

+1 para preferir excepciones sobre valores de retorno booleanos. Además, relativePathStr se puede calcular utilizando path.lexically_relative (sourceDir), que puede ser más fácil de leer que boost :: replace_first. – Philippe

2

Ya no necesita impulso para esa tarea ya que su biblioteca del sistema de archivos se ha incluido en C++ std con, p. Ej. la adición de 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. 
    } 
} 

Ver también std::filesystem::copy_options.

+0

Muchas gracias Roi. Espero que los visitantes se den cuenta de su respuesta. – Ant

+0

Tenga en cuenta que esto se agregó a ISO C++ en C++ 17. –

Cuestiones relacionadas