it-swarm.com.de

Wie kann ich ein Verzeichnis mit Boost Filesystem kopieren?

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.

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

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.

43
nijansen

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 .

12
Roi Danton

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).

10
Doineann

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 ()

0
GuidedHacking