C:递归打开子目录并创建新文件

时间:2014-05-19 12:26:14

标签: c recursion directory

我正在写一些递归找到.c和.h文件的内容并删除所有注释(就像学习练习一样)。对于找到的每个.c / .h文件,此程序创建一个额外的文件,该文件等于没有注释的原始文件。例如,“helloworld.c”会产生一个额外的文件“__helloworld.c”

我遇到的问题是:

我有一个循环遍历目录中的所有条目,并继续前进,直到它停止查找带.c或.h扩展名的文件。但是,循环永远不会实际结束,因为每次找到文件时,都会创建另一个文件。所以我有这种递归的情况,其中“__ helloworld.c”变成“____ helloworld.c”,变成“______ helloworld.c”等。 (如果有人建议,是的,新文件必须有.c扩展名。) 一种可能的解决方案可能是跟踪inode数量,因此我们只知道迭代原始文件,但是这需要循环的几次迭代:一次计算目录条目, (并使用此数字初始化inode nums的数组),两次存储inode数字,最后第三次用于完成工作。

任何人都可以分享任何可以在循环的单次传递中实现这一点的想法吗? 代码分为两个文件,所以我发布了主递归例程:

consume_comments():     将单个文件作为参数,创建省略注释的新文件

我的主要例程几乎就是做一些参数处理 - 下面发布的例程就是真正的问题所在。

/*
opens a directory stream of the dir pointed to by 'filename',
looks for .c .h files, consumes comments. If 'rc' == 1, find()
calls itself when it encounters a sub-directory.
*/
int find (const char * dirname)
{
        int count = 3;
        DIR * dh;
        struct dirent * dent;
        struct stat buf;
        const char * fnext;
        int filecount = 0;

        chdir(dirname);

        if ((dh = opendir(".")) == NULL)
        {
                printf("Error opening directory \"%s\"\n", dirname);
                exit(-1);
        }

        while ((dent = readdir(dh)) != NULL)
        {
                if (count) count--;
                if (!count)
                {
                        if (lstat(dent->d_name, &buf) == -1)
                        {
                                printf("Error opening file \"%s\" for lstat()\n", dent->d_name);
                                exit(EXIT_FAILURE);
                        }

                        if (S_ISDIR(buf.st_mode) && rc)
                        {
                                find(dent->d_name);
                                chdir("..");
                                //when this find() completes, it will be one level down:
                                //so we must come back up again.
                        }
                        if (S_ISREG(buf.st_mode))
                        {
                                fnext = fnextension(dent->d_name);
                                if (*fnext == 'c' || *fnext == 'h')
                                {
                                        consume_comments(dent->d_name);
                                        printf("Comments consumed:%20s\n", dent->d_name);
                                }
                        }
                }
        }
}

3 个答案:

答案 0 :(得分:4)

您可以使用3种解决方案中的1种

  1. 正如@Theolodis在评论中所建议的那样,忽略以。开头的文件 __
  2. 将算法拆分为两部分。在第一部分准备一份清单 所有.c.h文件(递归)。第二步,浏览列表 生成剥离的文件版本(非递归)。
  3. 在某个临时目录中准备剥离的.c.h文件 (在Linux中为/tmp或在Windows中为%TEMP%)并将其移至文件夹一次 已处理文件夹的所有.c.h个文件。现在 扫描所有子文件夹。

答案 1 :(得分:1)

我确实看到了您问题的多种解决方案。但无论如何,您可能需要检查您要创建的文件是否已存在!否则,您可能遇到覆盖现有文件的情况!

(示例:file.c__file.c在您的目录中,检查文件__file.c并生成文件____file.c,然后检查文件file.c并覆盖文件__file.c

  1. 忽略以您选择的前缀开头的文件。

    优点:易于实施

    缺点:你可能会错过一些以前缀

  2. 开头的文件
  3. 在浏览所有目录时,您创建了一组已创建的唯一文件名。在转换任何文件之前,请检查此文件是否由您自己创建。

    优点:您不会错过以前缀

    开头的文件

    缺点:如果你有一个很长的文件列表,内存使用可能会爆炸。

  4. 编辑:Mohit Jain的第二和第三个解决方案看起来也很不错!

答案 2 :(得分:1)

新实现,使用例程chk_prefix()匹配文件名的前缀。

char * prefix = "__nmc_";

int chk_prefix (char * name)
{
        int nsize = strlen(name);
        int fsize = strlen(prefix);
        int i;
        if (nsize < fsize) return 1;
        for (i = 0; i < fsize; i++)
        {
                if (name[i] != prefix[i]) return 1;
        }
        return 0;
}

int find (const char * dirname)
{
        int count = 3;
        DIR * dh;
        struct dirent * dent;
        struct stat buf;
        const char * fnext;
        int filecount = 0;

        chdir(dirname);

        if ((dh = opendir(".")) == NULL)
        {
                printf("Error opening directory \"%s\"\n", dirname);
                exit(-1);
        }

        while ((dent = readdir(dh)) != NULL)
        {
                if (count) count--;
                if (!count)
                {
                        if (lstat(dent->d_name, &buf) == -1)
                        {
                                printf("Error opening file \"%s\" for lstat()\n", dent->d_name);
                                exit(EXIT_FAILURE);
                        }

                        if (S_ISDIR(buf.st_mode) && rc)
                        {
                                find(dent->d_name);
                                chdir("..");
                                //when this find() completes, it will be one level down:
                                //so we must come back up again.
                        }
                        if (S_ISREG(buf.st_mode))
                        {
                                fnext = fnextension(dent->d_name);
                                if (*fnext == 'c' || *fnext == 'h' && chk_prefix(dent->d_name))
                                {
                                        consume_comments(dent->d_name);
                                        printf("Comments consumed:%20s\n", dent->d_name);
                                }
                        }
                }
        }
}