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
替换为 wstring
或 wchar_t *
并将此 entry.path().relative_path().string()
转换为 entry.path().relative_path().wstring()
和还有 cout
到 wcout
。还是不行。
也将 main
更改为 wmain( int argc, wchar_t *argv[ ])
或 wmain( int argc, wchar_t *argv[ ], wchar_t *envp[ ] )
,但仍然无法正常工作。
还在 main 函数后面添加了 setlocale(LC_ALL, "");
,正如 Whosebug 上的另一篇文章所说,但仍然没有改进。
我正在寻求帮助,因为我没有找到解决这个问题的方法,而且,更多的其他解决方案是将特殊的 unicode 字符打印到控制台,但我需要更多来处理它们(读取文件名和包含特殊 unicode 字符的路径)而不是打印它们。
不仅如此,在我尝试了上面提到的所有这些可能无效的解决方案之后,我将我的程序恢复到我刚刚在上面发布的原始代码,现在它根本无法正常工作。即使对于普通的拉丁字符,它也会说“没有这样的文件或目录”,并且不再复制或删除任何内容。
转到定义了std::filesystem::path
的头文件。
(可能在:PATH_TO_MINGW/usr/include/c++/YOUR_VERSION/bits/fs_path
)
寻找using value_type =
寻找定义最终使用哪个 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
,这应该可以解决您的问题。
我编写了一个程序,将文件从给定路径复制到另一个路径。它运行良好,直到遇到目录名或文件名中的特殊字符。在那一刻它停止并抛出“没有这样的文件或目录”的错误。
这是我到目前为止所做的:
#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
替换为 wstring
或 wchar_t *
并将此 entry.path().relative_path().string()
转换为 entry.path().relative_path().wstring()
和还有 cout
到 wcout
。还是不行。
也将 main
更改为 wmain( int argc, wchar_t *argv[ ])
或 wmain( int argc, wchar_t *argv[ ], wchar_t *envp[ ] )
,但仍然无法正常工作。
还在 main 函数后面添加了 setlocale(LC_ALL, "");
,正如 Whosebug 上的另一篇文章所说,但仍然没有改进。
我正在寻求帮助,因为我没有找到解决这个问题的方法,而且,更多的其他解决方案是将特殊的 unicode 字符打印到控制台,但我需要更多来处理它们(读取文件名和包含特殊 unicode 字符的路径)而不是打印它们。
不仅如此,在我尝试了上面提到的所有这些可能无效的解决方案之后,我将我的程序恢复到我刚刚在上面发布的原始代码,现在它根本无法正常工作。即使对于普通的拉丁字符,它也会说“没有这样的文件或目录”,并且不再复制或删除任何内容。
转到定义了
std::filesystem::path
的头文件。 (可能在:PATH_TO_MINGW/usr/include/c++/YOUR_VERSION/bits/fs_path
)寻找
using value_type =
寻找定义最终使用哪个
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
,这应该可以解决您的问题。