鱼C论坛

 找回密码
 立即注册
查看: 5502|回复: 37

关于opendir、readdir读取不了中文目录问题

[复制链接]
发表于 2023-7-24 20:48:31 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
问题如标题,网上说可以通过改编码格式改为UTF-8但是也没用,然后把电脑编码格式改为utf-8也不行,改为宽字符能读取数字和字母。中文还是读不出来


目的:通过该函数读取一个目录下的文件夹并将目录下的文件夹的名称保存到一个数组中便于后期输入查看。
                网上查到似乎只有这两函数(opendir、readdir、closedir)可以实现读取文件夹的信息。



再次向各位网友求助,感谢感谢!
不管信息是否能彻底解决都感谢各位的建议和帮助。

设备:window笔记本
软件:VS2019
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2023-7-24 20:48:52 | 显示全部楼层

回帖奖励 +2 鱼币

在使用 opendir 和 readdir 函数读取中文目录时,可能会出现乱码的问题。这是因为 readdir 函数返回的文件名是以ASCII编码表示的,而中文字符在ASCII编码范围之外,导致无法正确显示中文目录。

解决这个问题的一种方法是使用操作系统相关的API来实现文件夹的遍历。在Windows系统下,可以使用 FindFirstFileW 和 FindNextFileW 函数来读取中文目录。

下面是一个使用Windows API来读取中文目录并保存到数组的示例代码:
  1. #include <iostream>
  2. #include <vector>
  3. #include <windows.h>
  4. using namespace std;
  5. // 读取中文目录
  6. void readChineseDirectory(const wstring& dirPath, vector<wstring>& directories) {
  7.     WIN32_FIND_DATAW findData;
  8.     HANDLE hFind = FindFirstFileW((dirPath + L"/*").c_str(), &findData);
  9.     if (hFind != INVALID_HANDLE_VALUE) {
  10.         do {
  11.             if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  12.                 // 排除"."和".."目录
  13.                 if (wcscmp(findData.cFileName, L".") != 0 && wcscmp(findData.cFileName, L"..") != 0) {
  14.                     directories.push_back(findData.cFileName);  // 将目录名称保存到数组
  15.                 }
  16.             }
  17.         } while (FindNextFileW(hFind, &findData));
  18.         FindClose(hFind);
  19.     }
  20. }
  21. int main() {
  22.     wstring dirPath = L"路径";  // 填写待读取的目录路径,请使用宽字符字符串
  23.     vector<wstring> directories;
  24.     readChineseDirectory(dirPath, directories);
  25.     // 输出目录名称
  26.     for (const auto& directory : directories) {
  27.         wcout << directory << endl;
  28.     }
  29.     return 0;
  30. }
复制代码

需要注意的是,上述示例代码中的路径字符串使用了宽字符字符串( wstring 类型),这是因为Windows API需要以宽字符字符串的形式接受路径参数。

希望这可以解决你遇到的问题。如果还有其他疑问,请随时提问。求给个最佳答案,非常感谢
只要点击我的回复贴写着发表时间的那一栏的绿色按钮即可,点了奖赏2鱼币,最好请你出售附件(不过也支持评分)-->

                               
登录/注册后可看大图


此回答源于ChatGPT,若有不正确之处,请多包容
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-7-24 20:48:53 | 显示全部楼层
你遇到的问题是关于在 Windows 环境下使用 opendirreaddir 函数读取中文目录名时出现乱码或无法读取的情况。这可能是因为在 Windows 默认的文件系统编码是 CP936(GBK),而不是 UTF-8。

要解决这个问题,可以使用 Windows API 提供的宽字符版本的目录操作函数来实现读取中文目录名。以下是一个示例代码:

  1. #include <iostream>
  2. #include <windows.h>

  3. int main() {
  4.     const char* path = "目录路径";
  5.     WCHAR wpath[MAX_PATH];
  6.     MultiByteToWideChar(CP_UTF8, 0, path, -1, wpath, MAX_PATH);

  7.     WIN32_FIND_DATAW findData;
  8.     HANDLE hFind = FindFirstFileW(wpath, &findData);
  9.   
  10.     if (hFind == INVALID_HANDLE_VALUE) {
  11.         std::cout << "无法打开目录" << std::endl;
  12.         return 1;
  13.     }

  14.     do {
  15.         if (wcscmp(findData.cFileName, L".") != 0 && wcscmp(findData.cFileName, L"..") != 0) {
  16.             // 在这里可以将目录名保存到数组或进行其他处理
  17.             // 例如:std::wcout << findData.cFileName << std::endl;
  18.         }
  19.     } while (FindNextFileW(hFind, &findData));

  20.     FindClose(hFind);

  21.     return 0;
  22. }
复制代码


这段代码使用了 Windows API 中的宽字符版本的函数 FindFirstFileWFindNextFileW 来读取目录下的文件夹信息。首先,将路径从 UTF-8 编码转换为宽字符编码(WCHAR),然后使用 FindFirstFileW 函数打开目录并获取第一个文件夹的信息。接着,在一个 do-while 循环中,通过 FindNextFileW 函数遍历目录下的所有文件夹(排除 "." 和 "..")。你可以根据需要,将目录名保存到数组或进行其他处理。

希望这个回答对你有帮助。如有更多问题,请随时提问。
如果问题已经解决,请设置最佳答案
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-7-24 20:49:10 | 显示全部楼层
答案:

如果您在Windows上用C++使用opendir和readdir处理含有非ASCII字符(如中文)的路径和文件名,可能会遇到问题,因为Windows API主要使用宽字符编码(如UTF-16)来处理文件名,而不是UTF-8。

解决这个问题,您可以尝试用"_wopendir"和"_wreaddir"代替"opendir"和"readdir"。这些函数使用宽字符(wchar_t)而不是单字节字符,对于Windows上的中文路径和文件名更为适用。首先您需要将UTF-8编码的字符串转换为UTF-16编码,然后再传递给这些函数。

下面是一段示例代码:

  1. #include <locale>
  2. #include <codecvt>
  3. #include <dirent.h>
  4. #include <iostream>

  5. std::string convertToUtf8(const std::wstring& wstr)
  6. {
  7.     std::wstring_convert<std::codecvt_utf8<wchar_t>> myconv;
  8.     return myconv.to_bytes(wstr);
  9. }

  10. int main()
  11. {
  12.     std::string pathUtf8 = "您的中文路径";
  13.     std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
  14.     std::wstring pathWstr = converter.from_bytes(pathUtf8);

  15.     _WDIR* dir = _wopendir(pathWstr.c_str());

  16.     if (dir) {
  17.         struct _wdirent* ent;
  18.         while ((ent = _wreaddir(dir)) != NULL) {
  19.             std::cout << convertToUtf8(ent->d_name) << std::endl;
  20.         }
  21.         _wclosedir(dir);
  22.     }
  23.     else {
  24.         std::cout << "Error opening directory" << std::endl;
  25.     }

  26.     return 0;
  27. }
复制代码

在这段代码中,我们首先定义了一个将宽字符串转换为UTF-8编码字符串的函数convertToUtf8。然后在主函数中,我们将UTF-8编码的路径字符串转换为宽字符串,然后将其传递给"_wopendir"函数打开目录。在目录打开之后,我们可以使用"_wreaddir"来读取目录中的文件,并使用convertToUtf8函数将文件名转换为UTF-8编码,然后打印出来。

当然,您需要注意这个解决方案是针对Windows的,如果您在其他平台(如Linux,macOS等)上编程,可能需要考虑其他解决方案,例如使用boost::filesystem库,它提供了跨平台的文件和目录操作函数。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-7-24 20:49:51 | 显示全部楼层
ANSI编码格式也不行。
可能没有及时回复,还请见谅。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-7-24 20:53:30 | 显示全部楼层

回帖奖励 +2 鱼币

想入门的新人 发表于 2023-7-24 17:49
ANSI编码格式也不行。
可能没有及时回复,还请见谅。

通过使用opendir、readdir和closedir函数,可以读取目录下的文件夹名称并保存到数组中。下面是一个示例代码,你可以尝试在VS2019中运行它:


  1. #include <iostream>
  2. #include <string>
  3. #include <vector>
  4. #include <dirent.h>

  5. int main() {
  6.     std::string folderPath = "目录路径"; // 替换为你要读取的目录路径

  7.     std::vector<std::string> folderNames;

  8.     DIR* dir;
  9.     struct dirent* entry;

  10.     // 打开目录
  11.     dir = opendir(folderPath.c_str());
  12.     if (dir != NULL) {
  13.         // 读取目录中的文件和文件夹
  14.         while ((entry = readdir(dir)) != NULL) {
  15.             // 排除当前目录和上级目录
  16.             if (std::string(entry->d_name) == "." || std::string(entry->d_name) == "..") {
  17.                 continue;
  18.             }

  19.             // 判断是否是文件夹
  20.             if (entry->d_type == DT_DIR) {
  21.                 folderNames.push_back(entry->d_name);
  22.             }
  23.         }

  24.         closedir(dir);
  25.     } else {
  26.         std::cout << "无法打开目录!" << std::endl;
  27.         return 1;
  28.     }

  29.     // 输出文件夹名称
  30.     for (const auto& folderName : folderNames) {
  31.         std::cout << folderName << std::endl;
  32.     }

  33.     return 0;
  34. }
复制代码


请将`目录路径`替换为你要读取的目录的实际路径。运行该代码后,文件夹名称将保存在`folderNames`数组中并进行输出。希望这可以帮助到你!如果还有其他问题,请随时提问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-7-24 21:03:58 | 显示全部楼层
学习编程中的Ben 发表于 2023-7-24 20:48
在使用 opendir 和 readdir 函数读取中文目录时,可能会出现乱码的问题。这是因为 readdir 函数返回的文件 ...

使用的是宽字符,那需要把vs的编码格式调为多字节字符集是吧,由于太久没接触这方面有点忘记了,还请指教,谢谢
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-7-24 21:05:41 | 显示全部楼层
想入门的新人 发表于 2023-7-24 21:03
使用的是宽字符,那需要把vs的编码格式调为多字节字符集是吧,由于太久没接触这方面有点忘记了,还请指教 ...


回复你的代码我还没检查,不过我先回答你这个问题吧
对于使用宽字符的情况,确实需要将编码格式调整为多字节字符集(Multi-Byte Character Set,简称MBCS)。在Visual Studio中进行设置的步骤如下:

1. 打开 Visual Studio
2. 在菜单栏中选择 "项目(Project)",然后选择 "属性(Properties)"。
3. 在弹出的属性面板中,选择 "配置属性(Configuration Properties)"。
4. 在左侧面板中选择 "常规(General)"。
5. 在右侧面板中,找到 "字符集(Character Set)" 选项。
6. 将 "字符集(Character Set)" 设置为 "使用多字节字符集"(Use Multi-Byte Character Set)。

完成上述步骤后,编译和运行你的程序,就可以使用宽字符了。如果之前已经创建了项目,还需要重新生成解决方案才能使更改生效。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-7-24 21:14:23 | 显示全部楼层

回帖奖励 +2 鱼币

想入门的新人 发表于 2023-7-24 18:03
使用的是宽字符,那需要把vs的编码格式调为多字节字符集是吧,由于太久没接触这方面有点忘记了,还请指教 ...

是的,如果要处理宽字符,你需要将 Visual Studio 的编码格式设置为多字节字符集(Multibyte Character Set)。

你可以按照以下步骤进行设置:

1. 打开 Visual Studio 项目。
2. 在菜单栏中选择 "项目" -> "属性"。
3. 在属性对话框中,选择 "配置属性" -> "常规"。
4. 在右侧的 "字符集" 下拉菜单中,选择 "使用多字节字符集"。
5. 单击 "确定" 保存更改。

这样设置后,Visual Studio 将使用多字节字符集,可以正确处理宽字符。请注意,更改后可能需要重新编译项目。

希望这个解释能够帮助你。如有其他问题,请随时提问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-7-24 21:19:51 | 显示全部楼层
学习编程中的Ben 发表于 2023-7-24 21:05
回复你的代码我还没检查,不过我先回答你这个问题吧
对于使用宽字符的情况,确实需要将编码格式调整为 ...


                               
登录/注册后可看大图

                               
登录/注册后可看大图


  1. #define  _CRT_SECURE_NO_WARNINGS
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include "dirent.h"



  5. int main()
  6. {
  7.    // SetConsoleOutputCP(CP_UTF8);
  8.    

  9.     char path[256] = {0};
  10.     int fileNum = 0;
  11.     wchar_t wpath[256] = { 0 };

  12.      printf("Enter path to list files: ");
  13.      scanf("%s", path);
  14.      printf("[%s]\n", path);



  15.      
  16.      
  17.     DIR* pDir = NULL;
  18.     dirent* pent = NULL;

  19.     pDir = opendir(path);
  20.   

  21.     if (pDir == NULL) //
  22.     {
  23.         printf("打不开文件夹\n");
  24.         system("pause");
  25.         return -1;
  26.     }

  27.     while (1)
  28.     {
  29.         pent = readdir(pDir);
  30.         char tmpname[256] = { 0 };

  31.         if (pent != NULL)
  32.         {
  33.             //将wchar_t 转为 cahr
  34.           //  wcstombs(tmpname, pent->d_name, 256);

  35.             if (pent->d_type == DT_BLK)
  36.             {
  37.                
  38.                 printf("DT_BLK:%s\n", tmpname);
  39.             }
  40.             else if (pent->d_type == DT_CHR)
  41.             {
  42.                
  43.                 printf("DT_CHR:[%s]\n", tmpname);
  44.             }
  45.             else if (pent->d_type == DT_DIR)
  46.             {
  47.                 printf("DT_DIR:[%s]\n", tmpname);
  48.             }
  49.             else if (pent->d_type == DT_FIFO)
  50.             {
  51.                 printf("DT_FIFO:[%s]\n", tmpname);
  52.             }
  53.             else if (pent->d_type == DT_LNK)
  54.             {
  55.                 printf("DT_LNK:[%s]\n", tmpname);
  56.             }
  57.             else if (pent->d_type == DT_REG)
  58.             {
  59.                 printf("DT_REG:[%s]\n", tmpname);
  60.             }
  61.             else if (pent->d_type == DT_SOCK)
  62.             {
  63.                 printf("DT_UNKNOWN:[%s]\n", tmpname);
  64.             }
  65.             else
  66.             {
  67.                 printf("********:[%s]\n", tmpname);
  68.             }
  69.             fileNum++;
  70.         }
  71.         else
  72.         {
  73.             break;
  74.         }
  75.     }
  76.     closedir(pDir);

  77.     printf("FileNum:%d\n", fileNum);
  78.    

  79.    
  80.     system("pause");
  81.     return 0;
  82. }
复制代码


小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-7-24 21:22:42 | 显示全部楼层

回帖奖励 +2 鱼币

先领鱼币
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-7-24 21:23:20 | 显示全部楼层
我去鱼币
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-7-24 21:26:22 | 显示全部楼层
Mike_python小 发表于 2023-7-24 20:53
通过使用opendir、readdir和closedir函数,可以读取目录下的文件夹名称并保存到数组中。下面是一个示例代 ...

你好,感谢回复,刚刚试了一下你的程序,只能打印英文,不能打印中文,因为我的目录文件设置为英文所以可以读取,若是中文应该是不可以的,最后感谢你提供的帮助,谢谢!
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-7-24 21:27:15 | 显示全部楼层
想入门的新人 发表于 2023-7-24 18:26
你好,感谢回复,刚刚试了一下你的程序,只能打印英文,不能打印中文,因为我的目录文件设置为英文所以可 ...

咳咳,如果解决了你的问题,可以给个最佳答案吗
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-7-24 21:31:10 | 显示全部楼层
isdkz 发表于 2023-7-24 20:49
答案:

如果您在Windows上用C++使用opendir和readdir处理含有非ASCII字符(如中文)的路径和文件名,可 ...


                               
登录/注册后可看大图


你好,我试了一下你的代码,运行结果如此,感谢帮助,虽然打印出来了但是是乱码,我试了把vs改为多字节字符集结果一样的,最后感谢你的回复和帮助
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-7-24 21:42:36 | 显示全部楼层
Mike_python小 发表于 2023-7-24 21:27
咳咳,如果解决了你的问题,可以给个最佳答案吗

可以的
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-7-24 21:42:36 | 显示全部楼层

回帖奖励 +2 鱼币

小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2023-7-24 21:43:21 | 显示全部楼层
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-7-24 21:43:51 | 显示全部楼层

感谢!!!!
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-7-24 21:47:28 | 显示全部楼层
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-5-10 01:01

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表