Как я могу скопировать каталог с помощью Boost Filesystem - PullRequest
24 голосов
/ 21 декабря 2011

Как я могу скопировать каталог с помощью Boost Filesystem?Я пробовал boost :: filesystem :: copy_directory (), но это только создает целевой каталог и не копирует содержимое.

Ответы [ 4 ]

44 голосов
/ 21 декабря 2011
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;
}

Использование:

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)

Насколько я вижу,худшее, что может случиться, - это то, что ничего не происходит, но я ничего не буду обещать!Используйте на свой страх и риск.

Обратите внимание, что каталог, в который вы копируете, не должен существовать.Если каталоги в каталоге, который вы пытаетесь скопировать, не могут быть прочитаны (подумайте об управлении правами), они будут пропущены, но остальные все равно следует скопировать.

Обновление

Рефакторинг функции, соответствующей комментариям.Кроме того, функция теперь возвращает результат успеха.Он вернет false, если не будут соблюдены требования к указанным каталогам или любому каталогу в исходном каталоге, но не если один файл не может быть скопирован.

13 голосов
/ 18 октября 2017

Начиная с C ++ 17 вам больше не нужно повышать для этой операции, поскольку файловая система была добавлена ​​в стандарт.

Использование 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.
    }
}

См. Также std::filesystem::copy_options.

11 голосов
/ 25 августа 2016

Я вижу эту версию как улучшенную версию ответа @ nijansen.Он также поддерживает исходные и / или целевые каталоги как относительные.

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

Основными отличиями являются исключения вместо возвращаемых значений, использование recursive_directory_iterator и boost::replace_first для удаления общей частипуть итератора и использование boost::filesystem::copy() для правильной работы с различными типами файлов (например, с сохранением символических ссылок).

0 голосов
/ 28 ноября 2018

Это не Boost-версия, которую я использую на основе кода Doineann. Я использую std :: filesystem, но не могу использовать простой fs::copy(src, dst, fs::copy_options::recursive);, потому что я хотел отфильтровать, какие файлы копируются по расширению файла внутри цикла.

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()); - это рабочая замена без Boost для вызова boost :: replace_first (), используемая в другом ответе

...