You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

stat()函数目录识别异常:部分目录被误判为文件

问题描述

使用stat.h头文件和stat()函数读取并列出目录中的文件与目录时,出现以下异常:

  • 仅能识别当前目录和2个子目录为目录,其余路径正确的目录均被判定为文件
  • 预设目录中新增的目录无法被识别,但嵌套在已识别目录中的新增目录可正常识别

怀疑是stat函数使用不当导致问题,以下是两段测试用C代码(IDE为Dev-C++):


第一段测试代码

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <dirent.h>
#include <locale.h>
#include <sys/stat.h>
#include <wchar.h>

extern int errno;
int main(int argc, char *argv[]) {
    setlocale(LC_ALL,"Turkish");
    DIR* dp;
    struct dirent dirp;
    char test[9999];

    getcwd(test,9999);
    printf("FOLDERMAIN:%s\n",test);
    dp=opendir(".");
    searchDirectoryForString(dp,"Mat",test);

    return 0;
}

void searchDirectoryForString(DIR* dp,char* str,char* directoryname)
{
    int lineno=1,num=0;
    FILE* fp;
    struct dirent *file;
    char temp[99999];
    char buf[99999];
    char *rpath;
    rpath = calloc(99999,1);
    char path[99999];
    char* temppath;
    temppath = calloc(99999,1);
    int count = 0;
    char dirhold[100];
    char* dot;
    int line_num = 1;
    int find_result=0;
    static int check=0;

    DIR* fdp;
    if(dp==NULL)
    {
        printf("cant open");
    }
    struct stat filestat;

    while (file=readdir(dp)) {
        stat(file->d_name,&filestat);
        if(strcmp(file->d_name,"..")==0||(strcmp(file->d_name,".")==0))
            continue;
        if ( S_ISDIR(filestat.st_mode))
        {
            check++;
            printf("\n CHECK: %d\n",check);
            if(check!=1)
            {
                strcpy(temppath,directoryname);
                printf("temp:%s\n",directoryname);
                strcat(directoryname,"\\");
                strcat(directoryname,file->d_name);
                dot = strrchr(directoryname, '\\');
                strcpy(dirhold,dot);
                printf("DIR: %s\n",dirhold);
                printf("%s KLASÖR\n",directoryname);
                chdir(directoryname);
                dp=opendir(directoryname);
                if(dp==NULL)
                {
                    printf("2\n");
                }
                strcat(temppath,dirhold);
                searchDirectoryForString(dp,str,temppath);
            }
            else{
                strcpy(path,directoryname);
                strcat(directoryname,"\\");
                strcat(directoryname,file->d_name);
                dot = strrchr(directoryname, '\\');
                strcpy(dirhold,dot);
                printf("DIR: %s\n",dirhold);
                printf("%s FOLDER\n",directoryname);
                chdir(directoryname);
                dp=opendir(directoryname);
                if(dp==NULL)
                {
                    printf("2\n");
                }
                strcat(path,dirhold);
                searchDirectoryForString(dp,str,path);
            }
        }
        else
        {
            snprintf(buf,99999,"%s",directoryname);
            strcat(buf,"\\");
            strcat(buf,file->d_name);
            printf("%s FILE \n",buf);

            if(fp) {
                fclose(fp);
                strcpy(rpath," ");
            }
        }
    }
}

第二段MCVE代码

#include <locale.h>
#include <unistd.h>
#include <dirent.h>
#include <stdio.h>
#include <sys/stat.h>
#include <wchar.h>

int main(int argc, char *argv[]) {
    setlocale(LC_ALL,"Turkish");
    DIR* dp;
    struct dirent dirp;
    char test[9999];
    getcwd(test,9999);
    printf("FOLDERMAIN:%s\n",test);
    dp=opendir(".");
    listDir(dp,test);

    return 0;
}

int isDir(const char *name) {
    struct stat fileStat;
    return !stat(name, &fileStat) && S_ISDIR(fileStat.st_mode);
}

void listDir(DIR* dp,char* directoryname)
{
    struct dirent *file;
    char buf[99999];
    char* temppath;
    temppath = calloc(99999,1);
    int count = 0;
    char dirhold[100];
    char* dot;
    int line_num = 1;
    int find_result=0;
    static int check=0;
    char* dir;
    DIR* fdp;
    if(dp==NULL)
    {
        printf("cant open");
    }
    while (file=readdir(dp)) {
        if(strcmp(file->d_name,"..")==0||(strcmp(file->d_name,".")==0))
            continue;
        if (isDir(file->d_name))
        {
            check++;
            printf("\n CHECK: %d\n",check);

            strcpy(temppath,directoryname);
            printf("temp:%s\n",directoryname);
            strcat(directoryname,"\\");
            strcat(directoryname,file->d_name);
            dot = strrchr(directoryname, '\\');
            strcpy(dirhold,dot);
            printf("DIR: %s\n",dirhold);
            printf("%s FOLDER\n",directoryname);
            chdir(directoryname);
            dp=opendir(directoryname);
            if(dp==NULL)
            {
                printf("2\n");
            }

            strcat(temppath,dirhold);
            listDir(dp,temppath);
        }
        else
        {
            snprintf(buf,99999,"%s",directoryname);
            strcat(buf,"\\");
            strcat(buf,file->d_name);
            printf("%s FILE\n",buf);
        }
    }
}

问题根源与修复方案

核心问题

  1. stat使用相对路径错误:调用stat(file->d_name, ...)时,仅传入文件名而非完整路径。当通过chdir切换目录后,后续stat会去当前工作目录查找原目录的文件,必然失败,导致filestat未初始化,误判为文件。
  2. 修改传入的路径参数:直接对directoryname做strcat操作,破坏了上层递归的路径值,导致路径混乱。
  3. 工作目录未恢复:chdir进入子目录后未切回原目录,后续所有文件操作都基于子目录路径,完全偏离预期逻辑。

修复后的代码

#include <locale.h>
#include <unistd.h>
#include <dirent.h>
#include <stdio.h>
#include <sys/stat.h>
#include <string.h>
#include <stdlib.h>

// 使用完整路径判断是否为目录,并添加错误处理
int isDir(const char *fullPath) {
    struct stat fileStat;
    if (stat(fullPath, &fileStat) == -1) {
        perror("stat error");
        return 0;
    }
    return S_ISDIR(fileStat.st_mode);
}

void listDir(const char *currentDir) {
    DIR* dp = opendir(currentDir);
    if(dp == NULL) {
        perror("opendir error");
        return;
    }

    struct dirent *file;
    char fullPath[1024];
    char originalDir[1024];
    // 保存当前工作目录,用于后续恢复
    getcwd(originalDir, sizeof(originalDir));

    while ((file = readdir(dp)) != NULL) {
        if(strcmp(file->d_name, "..") == 0 || strcmp(file->d_name, ".") == 0)
            continue;

        // 拼接完整路径,避免相对路径错误
        snprintf(fullPath, sizeof(fullPath), "%s\\%s", currentDir, file->d_name);

        if (isDir(fullPath)) {
            printf("%s FOLDER\n", fullPath);
            // 递归遍历子目录
            listDir(fullPath);
        } else {
            printf("%s FILE\n", fullPath);
        }
    }

    closedir(dp);
    // 切回原工作目录,保证后续路径正确
    chdir(originalDir);
}

int main(int argc, char *argv[]) {
    setlocale(LC_ALL,"Turkish");
    char currentDir[1024];
    getcwd(currentDir, sizeof(currentDir));
    printf("FOLDERMAIN:%s\n", currentDir);
    listDir(currentDir);
    return 0;
}

关键修复点

  • 传递完整目录路径给遍历函数,不再依赖DIR*和工作目录切换
  • 始终使用完整路径调用stat,确保路径不受当前工作目录影响
  • 保存并恢复工作目录,避免路径混乱
  • 添加错误处理,方便排查opendir/stat的失败原因

内容的提问来源于stack exchange,提问作者user20137453

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 18:10:49