C++ 读取文件夹下的所有文件名

本文介绍了使用C++和_io.h_库中的函数读取指定文件夹内所有文件的方法,包括递归遍历子文件夹及获取文件信息。

C++读取整个文件夹里面的文件,如果你可以读完,可以发现很简单,先附上原文链接

http://blog.youkuaiyun.com/cxf7394373/article/details/7195661

先看第一个例子:这个例子比较复杂,是目录中还有目录的情况,如果要直接读取整个文件夹的文件,可以直接从_finddata_t 的使用开始看。

头文件:#include<io.h>

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. char * filePath = "D:\\sample";  
[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. vector<string> files;  
  2.   
  3. ////获取该路径下的所有文件  
  4. getFiles(filePath, files );  
  5.   
  6. char str[30];  
  7. int size = files.size();  
  8. for (int i = 0;i < size;i++)  
  9. {  
  10.     cout<<files[i].c_str()<<endl;  
  11. }  

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. void getFiles( string path, vector<string>& files )  
  2. {  
  3.     //文件句柄  
  4.     long   hFile   =   0;  
  5.     //文件信息  
  6.     struct _finddata_t fileinfo;  
  7.     string p;  
  8.     if((hFile = _findfirst(p.assign(path).append("\\*").c_str(),&fileinfo)) !=  -1)  
  9.     {  
  10.         do  
  11.         {  
  12.             //如果是目录,迭代之  
  13.             //如果不是,加入列表  
  14.             if((fileinfo.attrib &  _A_SUBDIR))  
  15.             {  
  16.                 if(strcmp(fileinfo.name,".") != 0  &&  strcmp(fileinfo.name,"..") != 0)  
  17.                     getFiles( p.assign(path).append("\\").append(fileinfo.name), files );  
  18.             }  
  19.             else  
  20.             {  
  21.                 files.push_back(p.assign(path).append("\\").append(fileinfo.name) );  
  22.             }  
  23.         }while(_findnext(hFile, &fileinfo)  == 0);  
  24.         _findclose(hFile);  
  25.     }  
  26. }  

_finddata_t 的使用  


那么到底如何查找文件呢?我们需要一个结构体和几个大家可能不太熟悉的函数。这些函数和结构体在<io.h>的头文件中,结构体为struct _finddata_t ,函数为_findfirst、_findnext和_fineclose。具体如何使用,我会慢慢讲来~
        首先讲这个结构体吧~ struct _finddata_t ,这个结构体是用来存储文件各种信息的。说实话,这个结构体的具体定义代码,我没有找到,不过还好,文档里面在_find里有比较详细的成员变量介绍。我基本上就把文档翻译过来讲吧:


        unsigned atrrib:文件属性的存储位置。它存储一个unsigned单元,用于表示文件的属性。文件属性是用位表示的,主要有以下一些:_A_ARCH(存档)、_A_HIDDEN(隐藏)、_A_NORMAL(正常)、_A_RDONLY(只读)、_A_SUBDIR(文件夹)、_A_SYSTEM(系统)。这些都是在<io.h>中定义的宏,可以直接使用,而本身的意义其实是一个无符号整型(只不过这个整型应该是2的几次幂,从而保证只有一位为1,而其他位为0)。既然是位表示,那么当一个文件有多个属性时,它往往是通过位或的方式,来得到几个属性的综合。例如只读+隐藏+系统属性,应该为:_A_HIDDEN | _A_RDONLY | _A_SYSTEM 。


        time_t time_create:这里的time_t是一个变量类型(长整型?相当于long int?),用来存储时间的,我们暂时不用理它,只要知道,这个time_create变量是用来存储文件创建时间的就可以了。


        time_t time_access:文件最后一次被访问的时间。


        time_t time_write:文件最后一次被修改的时间。


        _fsize_t size:文件的大小。这里的_fsize_t应该可以相当于unsigned整型,表示文件的字节数。


        char name[_MAX_FNAME]:文件的文件名。这里的_MAX_FNAME是一个常量宏,它在<stdlib.h>头文件中被定义,表示的是文件名的最大长度。


        以此,我们可以推测出,struct _finddata_t ,大概的定义如下:


        struct   _finddata_t
        {
             unsigned attrib;
             time_t time_create;
             time_t time_access;
             time_t time_write;
             _fsize_t size;
             char name[_MAX_FNAME];
        };


        前面也说了,这个结构体是用来存储文件信息的,那么如何把一个硬盘文件的文件信息“存到”这个结构体所表示的内存空间里去呢?这就要靠_findfirst、_findnext和_fineclose三个函数的搭配使用了。


        首先还是对这三个函数一一介绍一番吧……


        long _findfirst( char *filespec, struct _finddata_t *fileinfo );


        返回值:如果查找成功的话,将返回一个long型的唯一的查找用的句柄(就是一个唯一编号)。这个句柄将在_findnext函数中被使用。若失败,则返回-1。


        参数:


        filespec:标明文件的字符串,可支持通配符。比如:*.c,则表示当前文件夹下的所有后缀为C的文件。


        fileinfo :这里就是用来存放文件信息的结构体的指针。这个结构体必须在调用此函数前声明,不过不用初始化,只要分配了内存空间就可以了。函数成功后,函数会把找到的文件的信息放入这个结构体中。


        int _findnext( long handle, struct _finddata_t *fileinfo );


        返回值:若成功返回0,否则返回-1。


        参数:


        handle:即由_findfirst函数返回回来的句柄。


        fileinfo:文件信息结构体的指针。找到文件后,函数将该文件信息放入此结构体中。


       int _findclose( long handle );


        返回值:成功返回0,失败返回-1。


        参数:


        handle :_findfirst函数返回回来的句柄。



第二个例子:


        大家看到这里,估计都能猜到个大概了吧?先用_findfirst查找第一个文件,若成功则用返回的句柄调用_findnext函数查找其他的文件,当查找完毕后用,用_findclose函数结束查找。恩,对,这就是正确思路。下面我们就按照这样的思路来编写一个查找C:\WINDOWS文件夹下的所有exe可执行文件的程序。


        #include <stdio.h>
        #include <io.h>


        const char *to_search="C:\\WINDOWS\\*.exe";        //欲查找的文件,支持通配符


        int main()
        {
             long handle;                                                //用于查找的句柄
             struct   _finddata_t fileinfo;                          //文件信息的结构体
             handle=_findfirst(to_search,&fileinfo);         //第一次查找
             if(-1==handle)return -1;
             printf("%s\n",fileinfo.name);                         //打印出找到的文件的文件名
             while(!_findnext(handle,&fileinfo))               //循环查找其他符合的文件,知道找不到其他的为止
             {
                  printf("%s\n",fileinfo.name);
            }
             _findclose(handle);                                      //别忘了关闭句柄
             system("pause");
             return 0;
        }


        当然,这个文件的查找是在指定的路径中进行,如何遍历硬盘,在整个硬盘中查找文件呢?大家可以在网络上搜索文件递归遍历等方法,这里不再做进一步介绍。


        细心的朋友可能会注意到我在程序的末尾用了一个system函数。这个与程序本身并没有影响,和getchar()函数的作用相同,只是为了暂停一下,让我们能看到命令提示符上输出的结果而已。
<think>我们被要求使用C++读取指定文件夹下的所有文件名。根据提供的引用,有多种方法可以实现,主要分为Windows平台和Linux平台。由于不同操作系统的文件系统API不同,我们需要分别处理。 在Windows上,我们可以使用`<io.h>`中的`_findfirst`、`_findnext`和`_findclose`函数。这些函数可以遍历目录中的文件和子目录。 在Linux上,我们可以使用`<dirent.h>`中的`opendir`、`readdir`和`closedir`函数。 考虑到跨平台的需求,我们可以使用条件编译(`#ifdef`)来区分不同平台。 根据引用[1][3][4]提供的Windows实现,以及引用[2][5]提供的Linux实现,我们可以编写一个跨平台的函数。 注意:在Windows实现中,我们需要注意: - 使用`_A_SUBDIR`属性来判断是否是目录。 - 跳过当前目录(".")和上级目录("..")。 - 递归遍历子目录(如果用户需要的话)。但用户问题中只要求读取所有文件名,没有明确是否包含子目录。根据引用[1][3]的代码,它们递归遍历了子目录。而引用[2]则没有递归遍历子目录(它跳过了子目录)。 用户需求是“读取目录下所有文件名”,这里可以有两种理解: 1. 只读取当前目录下的文件(不包括子目录)。 2. 递归读取当前目录及其子目录下的所有文件。 由于引用中提供了两种不同的实现,我们需要明确用户的需求。但是,用户上一次的问题并没有明确是否包含子目录。因此,我们可以提供两种版本,或者询问用户。但这里我们根据问题描述“读取指定文件夹下的所有文件名”,通常可以理解为包括子目录(因为说“所有”),但也不绝对。 考虑到问题描述没有明确,而引用中多数包含了子目录,我们这里先实现一个递归遍历的版本(即包括子目录)。同时,我们也可以提供一个非递归的版本,并让用户选择。 但是,为了保持简洁,我们先按照递归遍历子目录的方式实现,因为引用[1][3]就是这样做的。 另外,引用[5]提到,在64位系统下,使用`long`作为文件句柄在Windows上可能有问题,应该使用`intptr_t`。 因此,我们编写一个跨平台的函数,递归获取指定目录下的所有文件(包括子目录中的文件)。 步骤: 1. 判断平台(Windows或Linux)。 2. 对于Windows,使用`_findfirst`、`_findnext`和`_findclose`,并递归处理子目录。 3. 对于Linux,使用`opendir`、`readdir`和`closedir`,并递归处理子目录。 注意:在Linux下,引用[2]的代码没有递归,所以我们需要修改为递归。同时,引用[2]中判断文件类型的方式是`ptr->d_type == 8`(8代表普通文件),但这种方式可能不是最可移植的,因为不同的文件系统可能返回不同的类型值。更可移植的方式是使用`DT_DIR`和`DT_REG`等宏,但注意不是所有系统都支持`d_type`。因此,另一种方法是使用`stat`函数来获取文件信息。 但是,为了简化,我们这里使用`d_type`,并且只处理普通文件和目录。对于不支持的`d_type`的情况,我们可以跳过(或者使用`stat`,但这样会增加复杂度)。考虑到性能,我们暂时使用`d_type`,并注意在无法确定类型时使用`stat`。 然而,根据POSIX标准,`d_type`并不是所有文件系统都支持,当不支持时,返回`DT_UNKNOWN`。所以,更可靠的方法是在遇到`DT_UNKNOWN`时使用`stat`。但为了代码简洁,我们假设常见的文件系统(如ext4)都支持`d_type`。如果用户需要更健壮的版本,可以自行修改。 因此,我们为Linux平台编写递归版本。 另外,用户可能只需要文件名(不包括路径),或者需要完整路径。根据引用中的代码,它们都存储了完整路径。我们这里也存储完整路径。 下面我们编写一个函数`getAllFiles`,它接受一个字符串路径和一个字符串向量引用,用于存储所有文件的完整路径。 注意路径分隔符:Windows使用反斜杠('\'),Linux使用正斜杠('/')。我们可以使用`std::filesystem::path::preferred_separator`来获得平台相关的分隔符,但为了减少依赖(C++17之前),我们手动处理:在Windows路径中使用"\\",在Linux中使用"/"。 但是,在代码中,我们可以用字符串连接,然后根据平台使用正确的分隔符。不过,我们可以使用以下方法: - 在Windows函数内部,我们使用"\\"。 - 在Linux函数内部,我们使用"/"。 这样,我们在各自平台使用各自的分隔符。 然而,为了代码清晰,我们分别写两个平台下的实现,并用条件编译包裹。 代码结构: ```cpp #include <vector> #include <string> #include <iostream> #ifdef _WIN32 #include <io.h> #include <windows.h> #else #include <dirent.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <cstring> #endif void getAllFiles(const std::string& path, std::vector<std::string>& files) { #ifdef _WIN32 // Windows实现 #else // Linux实现 #endif } ``` 现在,我们分别实现两个平台的部分。 Windows实现(参考引用[1][3]): - 使用`_findfirst`和`_findnext`遍历目录。 - 使用`_A_SUBDIR`判断是否是目录。 - 跳过"."和".."。 - 如果是目录,则递归调用。 - 如果是文件,则将完整路径添加到向量。 Linux实现(参考引用[2]并修改为递归): - 使用`opendir`打开目录。 - 使用`readdir`读取目录项。 - 跳过"."和".."。 - 如果遇到目录,则递归调用。 - 如果遇到普通文件,则添加完整路径。 注意:在Linux中,`d_type`可能为`DT_DIR`(目录)或`DT_REG`(普通文件),但还有其他类型(如符号链接等)。我们这里只考虑普通文件和目录。其他类型(如符号链接)可以按需处理,但这里我们忽略。 另外,在Linux中,目录项的类型可能为`DT_UNKNOWN`,这时我们需要调用`stat`来获取文件信息。但为了简单,我们暂时忽略这种情况,或者将`DT_UNKNOWN`视为普通文件?这可能会出错。所以,我们这里只处理明确是目录或普通文件的情况,其他情况跳过。 因此,我们编写如下代码: 注意:在Linux中,我们使用`dirent`结构体,其中`d_type`字段。我们检查: - `d_type == DT_DIR`:目录 - `d_type == DT_REG`:普通文件 但是,我们也可以将非目录都视为文件?这样可能不够严谨。根据需求,我们只想要文件,所以非目录且不是特殊文件,我们都可以视为文件?但这里我们保守处理:只处理普通文件和目录。 另外,在递归时,我们只对目录进行递归。 现在,我们编写代码: 由于代码较长,我们直接写在下面的回答中。 注意:在Windows中,路径使用宽字符还是多字节字符?这里我们使用多字节字符串(ANSI),因为参数是`std::string`。如果用户需要支持Unicode,可以使用宽字符,但这里为了简单,使用多字节。 另外,在Windows中,`_findfirst`和`_findnext`使用的模式是`*`,即匹配所有文件。 最后,我们提供一个测试函数,例如在main函数中调用并打印所有文件名。 但是,用户可能只需要函数,所以我们只提供函数,并给出使用示例。 下面给出完整代码示例(包括测试):</think>在 C++读取目录下所有文件名需要根据操作系统使用不同的 API。以下是跨平台实现方法(支持 Windows 和 Linux): ### 跨平台实现代码 ```cpp #include <iostream> #include <vector> #include <string> #ifdef _WIN32 #include <windows.h> #include <io.h> #else #include <dirent.h> #include <sys/types.h> #endif void getAllFiles(const std::string& path, std::vector<std::string>& files) { #ifdef _WIN32 // Windows 实现 intptr_t hFile = 0; struct _finddata_t fileinfo; std::string p = path + "\\*"; if ((hFile = _findfirst(p.c_str(), &fileinfo)) != -1) { do { if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0) { std::string fullPath = path + "\\" + fileinfo.name; if (fileinfo.attrib & _A_SUBDIR) { // 子目录 getAllFiles(fullPath, files); } else { // 文件 files.push_back(fullPath); } } } while (_findnext(hFile, &fileinfo) == 0); _findclose(hFile); } #else // Linux 实现 DIR* dir; struct dirent* ptr; if ((dir = opendir(path.c_str())) != nullptr) { while ((ptr = readdir(dir)) != nullptr) { if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) { continue; // 跳过 . 和 .. } std::string fullPath = path + "/" + ptr->d_name; if (ptr->d_type == DT_DIR) { // 目录 getAllFiles(fullPath, files); } else if (ptr->d_type == DT_REG) { // 普通文件 files.push_back(fullPath); } } closedir(dir); } #endif } // 示例用法 int main() { std::string folderPath = "/path/to/your/folder"; // 替换为实际路径 std::vector<std::string> fileList; getAllFiles(folderPath, fileList); // 打印所有文件名 for (const auto& file : fileList) { std::cout << file << std::endl; } return 0; } ``` ### 关键说明 1. **Windows 使用 `_findfirst`/`_findnext` API** - 通过 `_A_SUBDIR` 属性判断目录类型[^4] - 递归处理子目录 - 路径格式:`C:\\Folder\\file.txt` 2. **Linux 使用 `opendir`/`readdir` API** - 通过 `d_type` 判断文件类型(`DT_DIR`=目录, `DT_REG`=普通文件) - 路径格式:`/home/user/file.txt` 3. **特殊处理** - 跳过当前目录`.`和上级目录`..` - 支持递归遍历子目录 - 返回文件的完整绝对路径 ### 注意事项 1. **Windows 需链接库**:在 VS 项目中添加 `shlwapi.lib` 或编译时加 `-lshlwapi` 2. **路径分隔符**:Windows 用 `\`,Linux 用 `/` 3. **符号链接**:本代码未处理符号链接,需额外判断 `DT_LNK` 类型 4. **文件类型判断**:Linux 的 `d_type` 并非所有文件系统都支持,如需更精确判断可使用 `stat()` 系统调用[^5] > 示例输出: > ``` > C:\test\file1.txt > C:\test\subfolder\image.png > /home/user/docs/report.pdf > ```
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值