C++ 17 在 Windows 7 x64 上复制和删除名称中带有特殊字符的文件?

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

我编写了一个程序,将文件从给定路径复制到另一个路径。它运行良好,直到遇到目录名或文件名中的特殊字符。在那一刻它停止并抛出“没有这样的文件或目录”的错误。

这是我到目前为止所做的:


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

在 Google 上搜索并主要在 Whosebug 上搜索解决方案后,结论是 none 有效。

我尝试在它的顶部添加 #define UNICODE#define _UNICODE,但它给出了更多错误。

我还在 CLion 的 CMakeLists 中添加了 -municode 标志,但也没有工作(它编译但给出运行时错误)。

还尝试用 L"where possible" 将所有可能的 string 替换为 wstringwchar_t * 并将此 entry.path().relative_path().string() 转换为 entry.path().relative_path().wstring() 和还有 coutwcout。还是不行。

也将 main 更改为 wmain( int argc, wchar_t *argv[ ])wmain( int argc, wchar_t *argv[ ], wchar_t *envp[ ] ),但仍然无法正常工作。

还在 main 函数后面添加了 setlocale(LC_ALL, "");,正如 Whosebug 上的另一篇文章所说,但仍然没有改进。

我正在寻求帮助,因为我没有找到解决这个问题的方法,而且,更多的其他解决方案是将特殊的 unicode 字符打印到控制台,但我需要更多来处理它们(读取文件名和包含特殊 unicode 字符的路径)而不是打印它们。

不仅如此,在我尝试了上面提到的所有这些可能无效的解决方案之后,我将我的程序恢复到我刚刚在上面发布的原始代码,现在它根本无法正常工作。即使对于普通的拉丁字符,它也会说“没有这样的文件或目录”,并且不再复制或删除任何内容。

  1. 转到定义了std::filesystem::path的头文件。 (可能在:PATH_TO_MINGW/usr/include/c++/YOUR_VERSION/bits/fs_path

  2. 寻找using value_type =

  3. 寻找定义最终使用哪个 value_type 的编译器宏。

来自我系统版本的示例:

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

当宏 _GLIBCXX_FILESYSTEM_IS_WINDOWS 设置为 1 时,将使用 wchar_t,这应该可以解决您的问题。