【问题标题】:How to read a file name containing 'œ' as character in C/C++ on windows如何在 Windows 上的 C/C++ 中读取包含“-”作为字符的文件名
【发布时间】:2021-02-17 07:32:22
【问题描述】:

此帖子与此帖子不重复:dirent not working with unicode

因为我在不同的操作系统上使用它,我也不想做同样的事情。另一个线程试图简单地计算文件,我想访问更复杂的文件名。


我正在尝试通过 Windows 10 操作系统上的文件名检索数据信息。

为此,我使用dirent.h(外部c 库,但在c++ 中也非常有用)。

DIR* directory = opendir(path);
struct dirent* direntStruct;

if (directory != NULL)
{
    while (direntStruct = readdir(directory))
    {            
        cout << direntStruct->d_name << endl;
    }
}

此代码能够检索位于特定文件夹中的所有文件名(一个接一个)。而且效果很好!

但是当它遇到一个包含字符“œ”的文件时,事情就变得疯狂了:

例子:

grosse blessure au cœur.txt

在我的程序中读作:

GUODU0~6.TXT

我无法在字符串名称中找到原始数据,因为您可以看到我的字符串变量与当前文件名无关!

我可以重命名文件并且它可以工作,但我不想这样做,我只需要从该文件名中读取数据,这似乎是不可能的。我该怎么做?

【问题讨论】:

  • "我的字符串变量与当前文件名无关!"你确定吗? ;)
  • @cigien:糟糕的骗局。错误的问题描述,错误的平台,没有适用的解决方案......
  • @AsteroidsWithWings 嗯,问题描述似乎相同。还有,为什么你认为这个平台是错误的?
  • @cigien 因为这些答案适用于 Mac 和 Linux,而这个问题是关于 Windows 的?问题描述完全不同:另一个问题是关于readdir跳过文件;这个是关于接收 DOS“短路径”而不是完整路径。请在关闭之前完整阅读问题:请注意,这样做可能需要 3 分钟以上。 :)
  • @scohe001 GUODO0~6.txt 是您在 Windows 上找到的短路径。还有一个带有.txt 文件扩展名的提示(尽管这不是证据)。当你知道时,你就知道了。

标签: c++ c string


【解决方案1】:

在 Windows 上,您可以使用 FindFirstFile()FindFirstFileEx() 后跟 FindNextFile() 来读取返回文件名中带有 Unicode 的目录的内容。

【讨论】:

  • 这就是我所做的:HANDLE hFind; WIN32_FIND_DATAA data; string localpath = all_paths[i] + "*"; hFind = FindFirstFileA(localpath.c_str(), &amp;data); if (hFind != INVALID_HANDLE_VALUE) { do { printf("%s\n", data.cFileName); string testy = data.cFileName; } while (FindNextFileA(hFind, &amp;data)); FindClose(hFind); }
【解决方案2】:

短文件名

您收到的名称是8.3 short file name NTFS 为非 ascii 文件名生成的名称,因此不支持 unicode 的程序可以访问它们。

坚持dirent

如果 dirent 不支持 UTF-16,您最好的选择可能是更改您的库。

但是,根据库的实施情况,您可能有运气:

  • 在基于char 的Windows API 中添加/更改应用程序的清单以支持UTF-8。这需要最新版本的 Windows 10。
    见 MSDN: Use the UTF-8 code pageWindows - 应用程序 - UWP - 设计和 UI - 可用性 - 全球化和本地化下。

  • 使用 setlocale 将 C++ 运行时的代码页设置为 UTF-8

我不推荐这个,也不知道这样行不行。

生活在改变

使用std::filesystem 枚举目录内容。 一个简单的例子can be found here(参见“2017 年更新”)。

仅限 Windows

您可以使用FindFirstFileWFindNextFileW 作为支持UTF16 字符串的平台API。但是,使用 std::filesystem 几乎没有理由这样做(至少对于您的用例而言)。

【讨论】:

  • 感谢您的完整解释。我已经继续你链接的线程,文件系统在我的情况下不起作用,人们建议使用 experience::filesystem 到 2020 年它仍然无法工作。我无法让它工作。
  • 您在使用 Visual Studio 吗?哪个版本?
  • 是的,但无论如何我不需要WA 完成了这项工作。我现在可以读取文件名中的任何类型的字符:Test - 160 - Testament - Ton cœur est ici éééé ààà !!!!! ö ö à &amp;_-.mkv 在我的字符串变量中保持不变。
【解决方案3】:

如果您使用 C,请直接使用操作系统函数,特别是 FindFirstFileWFindNextFileW。注意末尾的W,您想使用这些函数的宽版本来取回完整的非ASCII 名称。

在 C++ 中,您有更多选择,特别是 Boost。您有像 recursive_directory_iterator 这样的类,它们允许跨平台文件搜索,它们提供 UTF-8/UTF-16 文件名。

编辑:绝对清楚,您从原始代码中获取的文件名是正确的。由于 Windows 文件系统(FAT32 和 NTFS)的向后兼容性,每个文件都有两个名称:“完整”、Unicode 识别名称和 DOS 时代的“旧”8.3 名称。

如果需要,您绝对可以使用 8.3 名称,只是不要将其显示给您的用户,否则他们会(正确地)感到困惑。或者只是使用适当的现代 API 来获取真实姓名。

【讨论】:

  • 谢谢,但是使用 W 它不允许我将结果转换为字符串,这将迫使我使用 wstring。问题是: wstring 不包含像 findreplace 这样的本机函数,这对我来说并不是很有帮助。编辑:我找到了一个修复 strID.find(L"LABS"); (我的坏)
  • 是的,你在说什么?无论如何你不能使用string,因为你提到的文件名首先没有ASCII表示,你需要一个UTF表示。
  • @Blindy “A”版本不是“ASCII”,而是“ANSI”,Windows 代码页将用于转换 128 到 255 之间的值。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-25
相关资源
最近更新 更多