【问题标题】:How to walk a directory in C如何在C中遍历目录
【发布时间】:2010-02-07 17:18:27
【问题描述】:

我在我的应用程序中使用 glib,我看到 glib 中有 C 的 remove、unlink 和 rmdir 的便利包装器。但这些只适用于单个文件或目录。

据我所知,C 标准和 glib 都不包含任何递归目录遍历功能。我也没有看到像rm -rf 那样一次删除整个目录树的任何特定方法。

对于我正在做的事情,我并不担心任何复杂性,例如权限、符号链接备份树(无限递归),或者任何会排除非常幼稚的事情 实现...所以我不反对为它编写自己的函数。

但是,我很好奇这个功能是否已经存在于标准库 gtk 或 glib(或其他一些易于重用的 C 库中)的某个地方,而我只是没有偶然发现它。谷歌搜索这个主题会产生很多虚假线索。

否则我的计划是使用这种类型的算法:

dir_walk(char* path, void* callback(char*) {
  if(is_dir(path) && has_entries(path)) {
    entries = get_entries(path);
    for(entry in intries) { dir_walk(entry, callback); }
  }
  else { callback(path) }
}

dir_walk("/home/user/trash", remove);

显然,我会构建一些错误处理等,以便在遇到致命错误时立即中止进程。

【问题讨论】:

  • 技术上只有remove()在C标准中,其他2个是POSIX :)
  • 除了现有的答案,请注意不要简单地将目录遍历目录进入魔多,无论是用 C 还是任何其他语言。
  • 除了现有的答案,我想指出健壮的代码不应该使用递归。请改用迭代和堆栈。

标签: c gtk glib directory-walk


【解决方案1】:

你看过<dirent.h>吗? AFAIK 这属于 POSIX 规范,它应该是大多数(如果不是所有)C 编译器的标准库的一部分。参见例如this <dirent.h> reference (Single UNIX specification Version 2 by the Open Group).

P.S.,在有人对此进行讨论之前:不,这不提供递归目录遍历。但是我认为这最好由开发人员实现;需求可能会有很大差异,因此一刀切的递归遍历函数必须非常强大。 (例如:符号链接是否跟进?是否应该限制递归深度?等)

【讨论】:

  • 在 windows 上它是 opendir/closedir 等。或 FindFirstFile FindNextFile.
【解决方案2】:

如果你想使用 glib,你可以使用 GFileEnumerator。

【讨论】:

  • GFileEnumerator 是递归的吗?我阅读了文档,但没有提到这一点。当然,我可以试一试就知道了……
  • 不,不是。可用的教程很少,但您应该看看gezeiten.org/post/2009/04/Writing-Your-Own-GIO-Jobs,它显示了递归文件列表(搜索“g_file_deep_count”)。
【解决方案3】:

几个平台包括 ftw 和 nftw:“(新)文件树遍历”。检查 imac 上的手册页表明这些是遗留的,新用户应该更喜欢 fts。便携性可能是这些选择中的任何一个的问题。

【讨论】:

    【解决方案4】:

    标准 C 库旨在提供原始功能。你所说的是复合行为。您可以使用您选择的 API 中的低级功能轻松实现它——take a look at this tutorial。

    【讨论】:

      【解决方案5】:

      请注意,您提到的 remove()、unlink() 和 rmdir() 的“便利包装器”,假设您指的是在 中声明的那些,并不是真正的“便利包装器”。用“g_”作为完全标准函数的前缀有什么方便? (请注意,即使我首先介绍了他们,我也会这么说。)

      这些包装器存在的唯一原因是 Windows 上的文件名问题,这些包装器实际上由真实代码组成;它们采用 Unicode 格式的文件名参数,以 UTF-8 编码。相应的“未包装”Microsoft C 库函数采用系统代码页中的文件名。

      如果您不是专门编写旨在移植到 Windows 的代码,则没有理由使用 g_remove() 等包装器。

      【讨论】:

      • 方便的是 g_ 版本可以处理您讨论的情况。由于我将 glib 和 gtk 用于许多其他事情,因此保持一致并使用 g_ 函数确实很有意义。不这样做可以确定我的代码将不可移植。我并不是要暗示 g_ 版本只是调用标准库。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-07
      • 2023-03-31
      • 2011-07-23
      • 2011-01-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多