linxu下c/c++遍历文件夹获取文件

11 篇文章 3 订阅

最近工作需要,需要遍历文件夹下的文件,但是我发现遇到两个非常有意思的问题,记录一下。
测试的平台为

PC linuxTina linux
Linux version 5.15.0-41-generic (buildd@lcy02-amd64-105) (gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0, GNU ld (GNU Binutils for Ubuntu) 2.34) #44~20.04.1-Ubuntu SMP Fri Jun 24 13:27:29 UTC 2022Linux version 4.9.191 (@AI-S003) (gcc version 6.4.1 (OpenWrt/Linaro GCC 6.4-2017.11 2017-11) ) #1 PREEMPT Tue Sep 6 02:14:55 UTC 2022
ubuntu全志

Tina linxu 和PC linux的运行结果不同,直接点,就是编译链不同导致的结果不同,linux 系统版本不一样,导致的结果也不一样 ,说了跟没说一样

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "time.h"
#include <iostream>
#include <math.h>
#include <vector>
#include <dirent.h>
#include <string.h>
#include<algorithm>
#include <sys/stat.h>
#include <sys/types.h>
#include <fstream> 
#include <cstdarg>
#include <vector>
using namespace std;

vector<string> files;

int getAbsoluteFiles(string path, vector<string>& filesAbsolutePath) 
 {
     DIR* dir = opendir(path.c_str());
     if ( dir == NULL ){
         cout<< path <<" is not a directory or not exist!"<<endl;
         return -1;
     }
 
     struct dirent* d_ent = NULL;       
     char fullpath[128] = {0};

     while ( (d_ent = readdir(dir)) != NULL ){
        if ( (strncmp(d_ent->d_name, "." ,1) != 0) ){
             if ( d_ent->d_type == DT_DIR ){
 
                 string newDirectory = path + string("/") + string(d_ent->d_name);
                 if( path[path.length()-1] == '/'){
                     newDirectory = path + string(d_ent->d_name);
                 }
                 if ( -1 == getAbsoluteFiles(newDirectory, filesAbsolutePath) ){
                     return -1;
                 }
             }else {
                 string absolutePath = path + string("/") + string(d_ent->d_name);
                   //如果传入的目录最后是/--> 例如a/b/  那么后面直接链接文件名
                 if( path[path.length()-1] == '/'){
                     absolutePath = path + string(d_ent->d_name); // /a/b/1.txt
                 }
                 filesAbsolutePath.push_back(absolutePath);
             }
         }
     }
    sort(filesAbsolutePath.begin(), filesAbsolutePath.end());
    closedir(dir);
    return 0;
 }


void listDir(char *path)
{
        DIR              *pDir ;
        struct dirent    *ent  ;
        int               i=0  ;
        char              childpath[512];
        pDir=opendir(path);
        memset(childpath,0,sizeof(childpath));
        while((ent=readdir(pDir))!=NULL)
        {
            if(ent->d_type & DT_DIR){
                if(strcmp(ent->d_name,".")==0 || strcmp(ent->d_name,"..")==0)
                    continue;
                sprintf(childpath,"%s/%s",path,ent->d_name);
                //printf("path:%s\n",childpath);
                listDir(childpath);
            }else{
                char fileName[1024] = {0};
                snprintf(fileName, 1024, "%s/%s",path,ent->d_name);
                //string fileName= path + "/" + ent->d_name;
                files.push_back(fileName);
            }
        }
        sort(files.begin(), files.end());
}

vector<string> getfiles(string strCurrentDir){
        vector<string> vFiles;
        DIR *dir;
        struct dirent *pDir;
        if((dir = opendir(strCurrentDir.c_str())) == NULL){
                cout << "open dir Faild" << endl;
                exit(1);
        }
 
        while((pDir = readdir(dir)) != NULL){
                if(strcmp(pDir->d_name,".")==0 || strcmp(pDir->d_name,"..")==0){
                        continue;
                }else if(pDir->d_type == DT_REG){ // 文件
                        vFiles.push_back(strCurrentDir + "/" + pDir->d_name);
                }else if(pDir->d_type == DT_UNKNOWN){
                        continue;
                }else if(pDir->d_type == DT_DIR){ // 子目录
                        string strNextdir = strCurrentDir + "/" + pDir->d_name;
                        vector<string> ss = getfiles(strNextdir);
                        vFiles.insert(vFiles.end(),ss.begin(),ss.end());
                }
        }
        closedir(dir);
        sort(vFiles.begin(), vFiles.end());
        return vFiles;
}

int main(int argc, char *argv[])
{
    char path[512] = {0};
    int flag = 0;
    if(argc == 3)
        flag = atoi(argv[2]);
    if(flag == 0)
        getAbsoluteFiles(argv[1],files);
    else if(flag == 1)
        listDir(argv[1]);
    else
        files = getfiles(argv[1]);

    for(vector<string>::iterator it = files.begin(); it != files.end();it++){
        string name = *it;
        cout << name.c_str()<<endl;
    }
    cout << "count " << files.size() << endl;
    return 0;
}


上述代码是三种不同的方式实现遍历文件夹,但是都大同小异,
下面是在pc linxu 的执行结果,其中test_image是测试文件路径,其中有多重子目录,

//0 代表执行的是getAbsoluteFiles
./a.out  ~/test_image/ 0
......
/test_image/xxx/xxxx/we-027.jpg
count 5407

//1 代表执行的是listDir
./a.out  ~/test_image/ 1
......
/test_image/xxx/xxxx/we-027.jpg
count 5407

//2 代表执行的是getfiles
./a.out  ~/test_image/ 2
......
/test_image/xxx/xxxx/we-027.jpg
count 5407

很明显结果没什么问题,但是当我移到Tina linux上时,结果如下

//0 代表执行的是getAbsoluteFiles
./a.out  ~/test_image/ 0
......
/test_image/xxx/xxxx/we-027.jpg
count 5407

//1 代表执行的是listDir
./a.out  ~/test_image/ 1
......
/test_image/xxx/xxxx/we-027.jpg
count 5411

//2 代表执行的是getfiles
./a.out  ~/test_image/ 2
......
/test_image/xxx/xxxx/we-021.jpg
count 1588

结果相差甚远

问题一:.和…被认为是普通文件

查看了下编译链的版本,交叉编译链是6.4.1 pc本地编译链是9.4.0,编译链的差距暂时是更改不了的,至于要怎么解决问题,只能从代码入手
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XKh4WDpR-1666854772903)(leanote://file/getImage?fileId=6359fbabce6ba65175000002)]

通过保存log文件来对比 getAbsoluteFileslistDir 的结果差异,发现是其中某个文件夹中的**.…**也被算进去了,
但是这里就有一个有意思的问题,test_image中有四个文件夹,唯独只有这一个文件夹出现这种情况,而且这四个文件夹本质上是一样的,不同的只是
里面的文件不同,为什么其他文件夹没有这个问题,而单独的就一个文件夹有问题,我至今都没有搞懂是什么原因。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-x1vBFT04-1666854772904)(leanote://file/getImage?fileId=6359fcb0ce6ba65175000003)]

仔细对别getAbsoluteFileslistDir, 发现getAbsoluteFiles是先排除**.,然后才进行目录和文件的判断。而listDir则是先判断文件和目录,只有是目录时才进行排除.…**
那是不是在交叉编译链中,有个时候或者说是在某种情况下会把**.当成文件,所以listDir才会出现这种情况,那直接在非目录的代码里加入排除.…**,看看效果


void listDir(char *path)
{
        DIR              *pDir ;
        struct dirent    *ent  ;
        int               i=0  ;
        char              childpath[512];
        pDir=opendir(path);
        memset(childpath,0,sizeof(childpath));
        while((ent=readdir(pDir))!=NULL)
        {
            if(ent->d_type & DT_DIR){
                if(strcmp(ent->d_name,".")==0 || strcmp(ent->d_name,"..")==0)
                    continue;
                sprintf(childpath,"%s/%s",path,ent->d_name);
                //printf("path:%s\n",childpath);
                listDir(childpath);
            }else{
                if(strcmp(ent->d_name,".")==0 || strcmp(ent->d_name,"..")==0)
                    continue;
                char fileName[1024] = {0};
                snprintf(fileName, 1024, "%s/%s",path,ent->d_name);
                //string fileName= path + "/" + ent->d_name;
                files.push_back(fileName);
            }
        }
        sort(files.begin(), files.end());
}

运行结果

//1 代表执行的是listDir
./a.out  ~/test_image/ 1
......
/test_image/xxx/xxxx/we-027.jpg
count 5407

现在就正确了,但是其中为什么会出现这个问题,我目前是说不出来一个所以然的,可能是知识面匮乏,暂时还不清楚。
目前只这样认为的:因为编译链和操作系统版本不一样,可能是版本相差太大的原因,底层的实现逻辑可能有很大的变化,对于目前的这个问题,可能是有些操作系统会把.和…认为是普通文件,而不是目录文件
但是又有点说不通,四个文件夹中为什么只有一个文件夹出现这个问题,我也看过文件夹有什么不同,但是并没有什么不同,权限也是一样的。如果有哪位大佬知道具体原因,麻烦指导一下。

问题二:有些文件被认为在不同的系统被认为的文件类型不一样

现在来看getfiles函数的实现,这个函数是根据得到的文件类型来进行判断,至于这些宏定义是什么意义,可以通过man来查看,如下图所示
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ydjJx2tj-1666854772904)(leanote://file/getImage?fileId=635a2497ce6ba65175000004)]

然后再pc端跑的结果和其他两个函数是正常的,但是在嵌入式平台上是及其不正常,少了很多文件,我们来做如下测试,把代码给成如下所示

vector<string> getfiles(string strCurrentDir){
        vector<string> vFiles;
        DIR *dir;
        struct dirent *pDir;
        if((dir = opendir(strCurrentDir.c_str())) == NULL){
                cout << "open dir Faild" << endl;
                exit(1);
        }
        
        while((pDir = readdir(dir)) != NULL){
                if(strcmp(pDir->d_name,".")==0 || strcmp(pDir->d_name,"..")==0){
                        continue;
                }else if(pDir->d_type == DT_DIR){ // 子目录
                        string strNextdir = strCurrentDir + "/" + pDir->d_name;
                        vector<string> ss = getfiles(strNextdir);
                        vFiles.insert(vFiles.end(),ss.begin(),ss.end());
                }else if(pDir->d_type == DT_REG){ // 文件
                        vFiles.push_back(strCurrentDir + "/" + pDir->d_name);
                }
                else
                {
                    cout << "else" << ":" << pDir->d_name <<endl;
                    else_count++;
                }
                
        }
        //cout << "else_count:" << else_count << endl;
        closedir(dir);
        sort(vFiles.begin(), vFiles.end());
        return vFiles;
}

我们来对比一下结果

//Ubuntu linux 
./a.out  ~/test_image/ 2
......
/test_image/xxxx/xxxx//we-027.jpg
count 5407
elsecount 0


//Tina linux 
./a.out  ~/test_image/ 2
......
/data/test_image/xxxx/xxxx/we-021.jpg
count 1588
elsecount 3819

结果如上,在Tina系统中,有三千多的文件被认为是其他类型的文件,我这些测试文件中全部都是.jpg文件,所以理论上类型应该是一样的,所以解决方法也很简单
,就是目录文件为一类,其他都当作普通文件即可,如下代码可以得到我们想要的结果

vector<string> getfiles(string strCurrentDir){
        vector<string> vFiles;
        DIR *dir;
        struct dirent *pDir;
        if((dir = opendir(strCurrentDir.c_str())) == NULL){
                cout << "open dir Faild" << endl;
                exit(1);
        }
        
        while((pDir = readdir(dir)) != NULL){
                if(strcmp(pDir->d_name,".")==0 || strcmp(pDir->d_name,"..")==0){
                        continue;
                }else if(pDir->d_type == DT_DIR){ // 子目录
                        string strNextdir = strCurrentDir + "/" + pDir->d_name;
                        vector<string> ss = getfiles(strNextdir);
                        vFiles.insert(vFiles.end(),ss.begin(),ss.end());
                }else{
                    vFiles.push_back(strCurrentDir + "/" + pDir->d_name);
                }
                
        }
        //cout << "else_count:" << else_count << endl;
        closedir(dir);
        sort(vFiles.begin(), vFiles.end());
        return vFiles;
}

目前得出的结论是,有些文件在不同的系统看来是不同类型的文件

正确代码

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "time.h"
#include <iostream>
#include <math.h>
#include <vector>
#include <dirent.h>
#include <string.h>
#include<algorithm>
#include <sys/stat.h>
#include <sys/types.h>
#include <fstream> 
#include <cstdarg>
#include <vector>
using namespace std;

vector<string> files;

int getAbsoluteFiles(string path, vector<string>& filesAbsolutePath) 
 {
     DIR* dir = opendir(path.c_str());
     if ( dir == NULL ){
         cout<< path <<" is not a directory or not exist!"<<endl;
         return -1;
     }
 
     struct dirent* d_ent = NULL;       
     char fullpath[128] = {0};

     while ( (d_ent = readdir(dir)) != NULL ){
        if ( (strncmp(d_ent->d_name, "." ,1) != 0) ){
             if ( d_ent->d_type == DT_DIR ){
 
                 string newDirectory = path + string("/") + string(d_ent->d_name);
                 if( path[path.length()-1] == '/'){
                     newDirectory = path + string(d_ent->d_name);
                 }
                 if ( -1 == getAbsoluteFiles(newDirectory, filesAbsolutePath) ){
                     return -1;
                 }
             }else {
                 string absolutePath = path + string("/") + string(d_ent->d_name);
                   //如果传入的目录最后是/--> 例如a/b/  那么后面直接链接文件名
                 if( path[path.length()-1] == '/'){
                     absolutePath = path + string(d_ent->d_name); // /a/b/1.txt
                 }
                 filesAbsolutePath.push_back(absolutePath);
             }
         }
     }
    sort(filesAbsolutePath.begin(), filesAbsolutePath.end());
    closedir(dir);
    return 0;
 }


void listDir(char *path)
{
        DIR              *pDir ;
        struct dirent    *ent  ;
        int               i=0  ;
        char              childpath[512];
        pDir=opendir(path);
        memset(childpath,0,sizeof(childpath));
        while((ent=readdir(pDir))!=NULL)
        {
            if(ent->d_type & DT_DIR){
                if(strcmp(ent->d_name,".")==0 || strcmp(ent->d_name,"..")==0)
                    continue;
                sprintf(childpath,"%s/%s",path,ent->d_name);
                //printf("path:%s\n",childpath);
                listDir(childpath);
            }else{
                if(strcmp(ent->d_name,".")==0 || strcmp(ent->d_name,"..")==0)
                    continue;
                char fileName[1024] = {0};
                snprintf(fileName, 1024, "%s/%s",path,ent->d_name);
                //string fileName= path + "/" + ent->d_name;
                files.push_back(fileName);
            }
        }
        sort(files.begin(), files.end());
}
int else_count = 0;
vector<string> getfiles(string strCurrentDir){
        vector<string> vFiles;
        DIR *dir;
        struct dirent *pDir;
        if((dir = opendir(strCurrentDir.c_str())) == NULL){
                cout << "open dir Faild" << endl;
                exit(1);
        }
        
        while((pDir = readdir(dir)) != NULL){
                if(strcmp(pDir->d_name,".")==0 || strcmp(pDir->d_name,"..")==0){
                        continue;
                }else if(pDir->d_type == DT_DIR){ // 子目录
                        string strNextdir = strCurrentDir + "/" + pDir->d_name;
                        vector<string> ss = getfiles(strNextdir);
                        vFiles.insert(vFiles.end(),ss.begin(),ss.end());
                }else{
                    vFiles.push_back(strCurrentDir + "/" + pDir->d_name);
                }
                
        }
        //cout << "else_count:" << else_count << endl;
        closedir(dir);
        sort(vFiles.begin(), vFiles.end());
        return vFiles;
}


int main(int argc, char *argv[])
{
    char path[512] = {0};
    int flag = 0;
    if(argc == 3)
        flag = atoi(argv[2]);
    if(flag == 0)
        getAbsoluteFiles(argv[1],files);
    else if(flag == 1)
        listDir(argv[1]);
    else
        files = getfiles(argv[1]);

    for(vector<string>::iterator it = files.begin(); it != files.end();it++){
        string name = *it;
        cout << name.c_str()<<endl;
    }
    cout << "count " << files.size() << endl;
    cout << "elsecount " << else_count << endl;
    return 0;
}


  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值