使用fts遍历文件系统(3)

时间:2012-09-26 20:22:38

标签: c linux unix filesystems traversal

我对fts(3)有疑问。每当我尝试访问fts_children()函数的任何成员时,我都会遇到分段错误。当我在http://www.kernel.org/doc/man-pages/online/pages/man3/fts.3.html阅读手册页时,它声称在读取函数运行后填充自己并返回通过结构中的link字段链接的链接列表。我的怀疑是child_function没有返回任何内容,但我觉得这不符合手册页。我应该将这些文件添加到子缓冲区,因为我认为这是自动完成的吗?我的代码如下, 谢谢!

#include<stdlib.h>
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fts.h>
#include<string.h>

int compare (const FTSENT**, const FTSENT**);

int main(int argc, char* const argv[])
{

        FTS* file_system = NULL;
        FTSENT* child = NULL;
        FTSENT* parent = NULL;
        FTSENT* temp = NULL;

        file_system = fts_open(argv + 1,FTS_COMFOLLOW | FTS_NOCHDIR,&compare);

        while( (parent = fts_read(file_system)) != NULL)
        {

             child = fts_children(file_system,0);
             printf("%s\n", child->fts_path);


        }
//      while (child ->fts_link != NULL)
      //         child = child->fts_link;
        fts_close(file_system);
        return 0;
}

int compare(const FTSENT** one, const FTSENT** two){
        return (strcmp((*one)->fts_name, (*two)->fts_name));
}
"test_fs.c" 43L, 1108C  

2 个答案:

答案 0 :(得分:5)

如果您只对遍历指定路径的所有目录和文件感兴趣,只需重复调用fts_read即可。

如果您只想遍历流,@ sehe的示例可以重写为:

#include<stdlib.h>
#include<stdio.h>
#include<sys/types.h>
#include<fts.h>
#include<string.h>
#include<errno.h>

int compare (const FTSENT**, const FTSENT**);
void indent (int i);

int main(int argc, char* const argv[])
{
    FTS* file_system = NULL;
    FTSENT *node,    = NULL;

    if (argc<2)
    {
        printf("Usage: %s <path-spec>\n", argv[0]);
        exit(255);
    }

    file_system = fts_open(argv + 1,FTS_COMFOLLOW|FTS_NOCHDIR,&compare);

    if (NULL != file_system)
    {
        while( (node = fts_read(file_system)) != NULL)
        {
            switch (node->fts_info) 
            {
                case FTS_D :
                case FTS_F :
                case FTS_SL:
                    indent(node->fts_level);
                    printf("%s\n", node->fts_name);
                    break;
                default:
                    break;
            }
        }
        fts_close(file_system);
    }
    return 0;
}

int compare(const FTSENT** one, const FTSENT** two)
{
    return (strcmp((*one)->fts_name, (*two)->fts_name));
}

void indent(int i)
{
    for (; i > 0; i--) 
        printf("    ");
}

当你运行它时,它会遍历流并按顺序列出所有文件和目录:

★ mkdir -p test/A/1 test/A/2 test/B/1 test/B/2

★ tree test                                   
test
├── A
│   ├── 1
│   └── 2
└── B
    ├── 1
    └── 2

★ ./fts test                                  
test
    A
        1
        2
    B
        1
        2

仅当您需要特定目录的子节点列表时才调用fts_children。在这种情况下,您必须至少致电fts_read一次,然后再致电fts_children;否则fts_children只会将argv参数中指定的节点返回fts_open

答案 1 :(得分:2)

您只需添加一个NULL检查。

你可能想要

  • file_system
  • 添加一个
  • 检查命令行参数
  • 添加更多错误处理:

      

    fts_children()函数返回指向FTSENT结构的指针,该结构描述目录中NULL终止的链接文件列表中的第一个条目,如果成功的话。 fts_children()函数可能会失败,并为errnochdir()malloc()opendir()和{{的任何错误设置readdir() 1}}函数指定。

更新到评论中的新问题:

  • 链接列表遍历的while循环错位(在外循环之外?)
  • printf仅显示路径...而不是文件名。

当你在它时:

stat()

示例输出片段:

#include<stdlib.h>
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fts.h>
#include<string.h>
#include<errno.h>

int compare (const FTSENT**, const FTSENT**);

int main(int argc, char* const argv[])
{
    FTS* file_system = NULL;
    FTSENT* child = NULL;
    FTSENT* parent = NULL;

    if (argc<2)
    {
        printf("Usage: %s <path-spec>\n", argv[0]);
        exit(255);
    }

    file_system = fts_open(argv + 1,FTS_COMFOLLOW | FTS_NOCHDIR,&compare);

    if (NULL != file_system)
    {
        while( (parent = fts_read(file_system)) != NULL)
        {
            child = fts_children(file_system,0);

            if (errno != 0)
            {
                perror("fts_children");
            }

            while ((NULL != child)
                && (NULL != child->fts_link))
            {
                child = child->fts_link;
                printf("%s%s\n", child->fts_path, child->fts_name);
            }
        }
        fts_close(file_system);
    }
    return 0;
}

int compare(const FTSENT** one, const FTSENT** two)
{
    return (strcmp((*one)->fts_name, (*two)->fts_name));
}