Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/58.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在C中使用scandir()递归列出已排序的子目录_C_Linux_Recursion_Scandir_Dirent.h - Fatal编程技术网

如何在C中使用scandir()递归列出已排序的子目录

如何在C中使用scandir()递归列出已排序的子目录,c,linux,recursion,scandir,dirent.h,C,Linux,Recursion,Scandir,Dirent.h,我正在用C实现Linux ls命令的一部分。我想按字典顺序对目录的内容进行排序,我一直在使用scandir()。这对于列出单个目录来说很容易,但是对于递归地列出子目录,我遇到了麻烦。我的当前代码:(一旦达到目录类型,就会导致分段错误) void递归(char*arg){ int i; 结构目录**文件列表; int-num; char*next_dir; num=scandir(arg,&file\u list,NULL,alphasort); 对于(i=0;id\u类型==DT\u目录){ 如

我正在用C实现Linux ls命令的一部分。我想按字典顺序对目录的内容进行排序,我一直在使用
scandir()
。这对于列出单个目录来说很容易,但是对于递归地列出子目录,我遇到了麻烦。我的当前代码:(一旦达到目录类型,就会导致分段错误)

void递归(char*arg){
int i;
结构目录**文件列表;
int-num;
char*next_dir;
num=scandir(arg,&file\u list,NULL,alphasort);
对于(i=0;id\u类型==DT\u目录){
如果(strcmp(“.”,文件列表[i]>d\u名称)!=0和strcmp(“…”,文件列表[i]>d\u名称)!=0){
//目录用冒号打印以区别于文件
printf(“%s:\n”,文件列表[i]->d\u名称);
strcpy(下一个目录,arg);
strcat(下一个目录“/”;
strcat(下一个目录,文件列表[i]>d\u名称);
printf(“\n”);
递归(next_dir);
}
}否则{
如果(strcmp(“.”,文件列表[i]>d\u名称)!=0和strcmp(“…”,文件列表[i]>d\u名称)!=0){
printf(“%s\n”,文件列表[i]->d\u名称);
}
}
}
} 
内部主(空){
递归(“.”);
返回0;
}

在Linux和其他POSIXy系统中,建议使用两种方法遍历整个文件系统树:

  • man 3 nftw

    给定初始路径、回调函数、要使用的最大描述符数和一组标志,
    nftw()
    将为子树中的每个文件系统对象调用回调函数一次。但是,没有指定调用同一目录中的条目的顺序

    这是POSIX.1(IEEE 1003)函数

  • man 3 fts

    fts接口提供了一种遍历文件系统层次结构的方法。
    fts_children()
    提供文件系统条目的链接列表,这些条目按照
    fts_open()
    调用中指定的比较函数排序。它与
    scandir()
    返回文件系统条目数组的方式非常相似,只是两者使用非常不同的结构来描述每个文件系统条目

    在glibc 2.23(2016年发布)之前,Linux(glibc)fts实现在使用64位文件大小时(在x86-64上也是如此,或者在使用
    -D_file_OFFSET_BITS=64
    编译时)存在缺陷

    这些是BSD函数(FreeBSD/OpenBSD/macOS),但在Linux中也可以使用

最后,还有scandir()的atfile版本,它从特定目录返回经过筛选和排序的文件系统条目,但除了路径名之外,它还将相对根目录的文件描述符用作参数。(如果使用
AT_FDCWD
而不是文件描述符,则
scandirat()
的行为类似于
scandir()

这里最简单的选择是使用
nftw()
,存储所有行走路径,最后对路径进行排序。例如,
walk.c

//SPDX许可证标识符:CC0-1.0
#定义_POSIX_C_源200809L
#定义GNU源
#包括
#包括
#包括
#包括
#包括
#包括
结构条目{
/*在此处插入其他属性,如“off\t size”*/
char*name;/*始终指向路径名的名称部分*/
字符路径名[];/*完整路径和名称*/
};
结构列表{
大小\u t max;/*分配给*/
size\u t num;/*数组中的条目数*/
结构项**ent;/*指针数组,每个项一个*/
};
#定义结构\u清单\u初始值设定项{0,0,NULL}
/*结构入口指针数组的区域设置感知排序。
*/
静态int entrysort(常数void*ptr1,常数void*ptr2)
{
常量结构项*ent1=*(常量结构项**)ptr1;
常量结构项*ent2=*(常量结构项**)ptr2;
返回strcoll(ent1->pathname,ent2->pathname);
}
/*nftw_add()用于添加到列表中的全局变量*/
静态结构列表*nftw_listing=NULL;
静态int-nftw_-add(常量字符*路径名,常量结构stat*信息,int-typeflag,结构FTW*ftwbuf)
{
const char*name=pathname+ftwbuf->base;
/*它们不生成代码,只会使有关未使用参数的警告静音*/
(无效)信息;
(作废)类型标志;
/*忽略“.”和“.”*/
如果(名称[0]='.&&!名称[1])
返回0;
如果(名称[0]='.&&name[1]='.&&&name[2])
返回0;
/*确保列表中至少还有一个条目的空间*/
如果(nftw_列表->数值>=nftw_列表->最大值){
const size\u t new\u max=nftw\u listing->num+1000;
结构条目**新建;
new_ent=realloc(nftw_listing->ent,new_max*sizeof(struct entry*));
如果(!新建)
return-ENOMEM;
nftw\u列表->最大值=新的\u最大值;
nftw\u列表->ent=新的\u ent;
}
常量大小\u t路径名len=strlen(路径名);
结构条目*ent;
/*为此项分配内存。
请记住说明名称,以及名称末尾的字符串终止符“\0”*/
ent=malloc(sizeof(struct entry)+pathnamelen+1);
如果(!ent)
return-ENOMEM;
/*将其他文件系统条目属性复制到此处的ent;例如“ent->size=info->st_size;”*/
/*复制路径名,包括字符串结束符“\0”*/
memcpy(ent->pathname,pathname,pathnamelen+1);
/*名称指针始终指向路径名中的*/
ent->name=ent->pathname+ftwbuf->base;
/*附加*/
nftw_listing->ent[nftw_listing->num++]=ent;
返回0;
}
/*从路径开始扫描目录树,将条目添加到结构列表中。
void recursive(char* arg){





    int i;
    struct dirent **file_list;
    int num;
    char* next_dir;

    num = scandir(arg, &file_list, NULL, alphasort);

    for(i = 0; i < num; i++) { 


        if(file_list[i]->d_type == DT_DIR) {

            if(strcmp(".", file_list[i]->d_name) != 0 && strcmp("..", file_list[i]->d_name) != 0) {


                        // Directories are printed with a colon to distinguish them from files

                        printf("%s: \n", file_list[i]->d_name);
                        strcpy(next_dir, arg);
                        strcat(next_dir, "/");
                        strcat(next_dir, file_list[i]->d_name);

                        printf("\n");

                        recursive(next_dir);
            }

        } else {

            if(strcmp(".", file_list[i]->d_name) != 0 && strcmp("..", file_list[i]->d_name) != 0) {

                printf("%s \n", file_list[i]->d_name);
            }
        }
    }



} 

int main(void) {

    recursive(".");


    return 0;
}