web-dev-qa-db-fra.com

Comment puis-je copier un répertoire en utilisant Boost Filesystem

Comment copier un répertoire avec Boost Filesystem? J'ai essayé boost :: filesystem :: copy_directory () mais cela ne crée que le répertoire cible et ne copie pas le contenu.

23
Ant
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;
}

Utilisation:

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)

Pour autant que je sache, le pire qui puisse arriver est que rien ne se passe, mais je ne promets rien! À utiliser à vos risques et périls.

Veuillez noter que le répertoire que vous copiez ne doit pas exister. Si les répertoires du répertoire que vous essayez de copier ne peuvent pas être lus (pensez à la gestion des droits), ils seront ignorés, mais les autres doivent tout de même être copiés.

Mettre à jour

Refactorisé la fonction respective aux commentaires. De plus, la fonction retourne maintenant un résultat de succès. Il renverra false si la configuration requise pour les répertoires donnés ou pour tout répertoire du répertoire source n'est pas remplie, mais pas si un seul fichier n'a pas pu être copié.

43
nijansen

Depuis C++ 17, vous n'avez plus besoin de boost pour cette opération car un système de fichiers a été ajouté à la norme.

Utilisez 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.
    }
}

Voir aussi std::filesystem::copy_options .

12
Roi Danton

Je vois cette version comme une version améliorée de la réponse de @ nijansen. Il prend également en charge que les répertoires source et/ou de destination soient relatifs.

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

Les principales différences sont les exceptions au lieu des valeurs de retour, l'utilisation de recursive_directory_iterator et boost::replace_first pour effacer la partie commune du chemin de l'itérateur, et s'appuyer sur boost::filesystem::copy() pour faire ce qu'il faut avec différents types de fichiers (préservation des liens symboliques, par exemple).

10
Doineann

J'utilise une version non Boost basée sur le code de Doineann. J'utilise std :: filesystem mais je n'ai pas pu utiliser un simple fs::copy(src, dst, fs::copy_options::recursive); car je voulais filtrer les fichiers copiés par extension de fichier à l'intérieur de la boucle.

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()); est un remplacement sans Boost pour l’appel boost :: replace_first () utilisé dans l’autre réponse

0
GuidedHacking