'C++ 17 copy and delete files with special characters in their names on Windows 7 x64?

I wrote a program that copy a file from a given path(s) to another. It runs well until it meets special character in directory names or in file names. At that moment it stops and throws the error that "No such file or directory".

This is what I done until now:


#include <iostream>
#include <vector>
#include <filesystem>
#include <cxxabi.h>
#include <string>
#include <sstream>
#include <memory>
#include <windows.h>
#include <chrono>
#include <thread>

using namespace std;
namespace fs = std::filesystem;


int main(int argc, char **argv) {
    vector<string> args(argv + 1, argv + argc);

    auto target = args[args.size() - 1];
    fs::path path = target;
    cout << "Destination path: " << target << endl;
    args.erase(args.end());
    for (const auto &source : args) {
        try {
            for (const auto &entry : fs::recursive_directory_iterator(source)) {
                std::string new_path = target + "\\" + entry.path().relative_path().string();
                //if entry is directory:
                while (true) {
                    if (GetDriveType(const_cast<char *>(path.root_path().string().c_str())) != DRIVE_NO_ROOT_DIR) {
                        if (fs::is_directory(entry)) {
                            //only if it NOT exists:
                            if (!fs::exists(new_path)) {
                                //create it only if not empty:
                                if (!fs::is_empty(entry)) {
                                    //Creating directory tree structure with empty folders:
                                    try {
                                        fs::create_directories(new_path);
                                    } catch (const std::exception &e) // caught by reference to base
                                    {
                                        std::cout << "When trying to create directory" << new_path
                                                  << "A standard exception was caught, with message '"
                                                  << e.what() << "'\n";
                                    }
                                }
                            }
                        }
                        break;
                    } else {
                        cout << "Destination path is not available. Sleeping for 3 minutes!" << endl;
                        std::this_thread::sleep_for(180000ms);
                    }
                }

                while (true) {
                    if (GetDriveType(const_cast<char *>(path.root_path().string().c_str())) != DRIVE_NO_ROOT_DIR) {
                        if ((fs::is_regular_file(entry)) && (fs::exists(entry))) {
                            if (!fs::is_empty(entry)) {
                                if (!fs::exists(new_path)) {
                                    //file does NOT exists in new path:
                                    try {
                                        fs::copy_file(entry.path().string(), new_path);
                                        cout << "Copy file: " << entry.path().string() << endl;
                                        fs::remove(entry);
                                    } catch (const std::exception &e) // caught by reference to base
                                    {
                                        std::cout
                                                << "When trying to get file size and source a standard exception was caught, with message '"
                                                << e.what() << "'\n";
                                    }


                                } else {
                                    //if it exists in new path:
                                    //first try to get file size and if this gives an error then do not copy:
                                    if (fs::file_size(entry.path().string()) >
                                        fs::file_size(entry.path().string())) {
                                        try {
                                            fs::copy_file(entry.path().string(), new_path);
                                            cout << "Replacing file: " << entry.path().string() << endl;
                                            fs::remove(entry);
                                        } catch (const std::exception &e) // caught by reference to base
                                        {
                                            std::cout
                                                    << "When trying to get file size and source a standard exception was caught, with message '"
                                                    << e.what() << "'\n";
                                        }
                                    }
                                }
                            }

                        }
                        break;
                    } else {
                        cout << "Destination path is not available. Sleeping for 3 minutes!" << endl;
                        std::this_thread::sleep_for(180000ms);
                    }
                }//end while!

            }
        } catch (const std::exception &e) // caught by reference to base
        {
            std::cout << "When recursive through directory tree a standard exception was caught, with message '"
                      << e.what() << "'\n";
        }
    }
    return 0;
}

After searching on Google and mostly on stackoverflow for a solution conclusion is that none works.

I tried adding #define UNICODE and #define _UNICODE at the top of it but it gives even more errors.

I also added -municode flag in CMakeLists in CLion but also not working (it compiles but gives runtime error).

Also tried to replace all possible string to wstring or wchar_t * with L"where possible" and to convert this entry.path().relative_path().string() to entry.path().relative_path().wstring() and also cout to wcout. Still not working.

Also changed main to wmain( int argc, wchar_t *argv[ ]) or to wmain( int argc, wchar_t *argv[ ], wchar_t *envp[ ] ) and still not working.

Also added setlocale(LC_ALL, ""); after the main function as the other article on stackoverflow says and still no improvement.

I am asking for help because I didn't find a solution for this problem and also, more of the other solution are for printing special unicode characters to console but I need more to work with them (read files names and paths that contain special unicode characters) instead of printing them.

More than this, after I tried all of these possible not working solutions I am talking about above and reverted my program back to the original code that I just posted above now it is not working at all. It says "no such file or directory" even for normal latin characters and doesn't copy or delete anything at all anymore.



Solution 1:[1]

  1. Go to the header file in which std::filesystem::path is defined. (possibly in: PATH_TO_MINGW/usr/include/c++/YOUR_VERSION/bits/fs_path)

  2. Look for using value_type =

  3. Look for compiler macros that define which value_type is ultimately used.

an example from the version from my system:

#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
    using value_type = wchar_t;
    static constexpr value_type preferred_separator = L'\\';
#else

When the macro _GLIBCXX_FILESYSTEM_IS_WINDOWS is set to 1 then a wchar_t will be used, which should solve your issue.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1