【Linux系统编程】深入理解Linux目录扫描函数:scandir目录函数(按条件扫描目录

简介: 【Linux系统编程】深入理解Linux目录扫描函数:scandir目录函数(按条件扫描目录

引言

Linux系统编程中,目录操作是一个常见的任务。本文将详细介绍scandir, scandirat, alphasort, 和 versionsort这几个用于目录扫描的函数。我们将从函数原型、参数说明、返回值,到内存分配等方面进行全面解析。

正如Bjarne Stroustrup在《The C++ Programming Language》中所说:“程序设计不仅仅是我们告诉计算机要做什么,更是关于我们如何组织复杂性。”

scandir函数详解

函数原型

#include <dirent.h>
int scandir(const char *dirp, struct dirent ***namelist,
              int (*filter)(const struct dirent *),
              int (*compar)(const struct dirent **, const struct dirent **));

参数说明

  • dirp:指定扫描的目录
  • namelist:struct dirent结构体类型的三级指针,用于获取该函数内部为存放返回结果的分配的动态内存,动态分配内存结构如图2-1所示.
  • filter:函数指针,指向过滤模式函数,当filter指针设置为NULL时,扫描dirp目录下的所有顶层文件.该函数有一个参数const struct dirent *是指在遍历过程中所遍历到的每一个子目录dirent,filter可以根据dirent的类型、名称等信息来判定当前的dirent是否为合法的子目录,合法则函数返回0,则该子目录的名称会被存储在namelist中;否则返回非0,则该子目录被过滤掉。
  • compar:函数指针,指向对遍历结果进行排序函数,alphasort函数和versionsort是经常用到的函数.
内存分配(Memory Allocation)

如图2-1所示,分配的内存包含两个部分:

  1. 一部分是struct dirent类型指针(一段连续内存,可看成指针数组),用于指向malloc分配用来存放目录信息内存地址,
  2. 另一部分是malloc分配struct dirent大小内存,存放遍历目录或文件的相关信息。
    若想获取目录相关信息,需要先获取指向该存放内存的指针,即图2-1中的strcut dirent *arr[N]指针数组地址。

返回值

scandir() 函数返回被选择的目录条数,或者如果出错返回 -1。

scandirat函数详解

函数原型

#include <fcntl.h>          /* Definition of AT_* constants */
#include <dirent.h>
int scandirat(int dirfd, const char *dirp, struct dirent ***namelist,
              int (*filter)(const struct dirent *),
              int (*compar)(const struct dirent **, const struct dirent **));

描述

scandirat()scandir()的扩展函数,主要区别在于第一个参数dirfd与第二个参数dirp

如果dirp是一个绝对路径的字符串,则函数无视参数dirfd,功能与scandir()一致。

如果dirp是一个相对路径的字符串,且参数dirfd的值是AT_FDCWD (#include ),则表示从应用程序当前的工作路径拼接上dirp的相对路径所组成的绝对路径下去遍历;

当dirfd值不为AT_FDCWD时而是一个代替文件夹的file descriptor(参考dirfd(DIR*))时,则遍历的文件夹路径即为dirfd所指向的文件夹再拼接上dirp的相对路径所组成的绝对路径。

示例

#define _DEFAULT_SOURCE
#include <dirent.h>
 #include <stdio.h>
#include <stdlib.h>
int main(void)
       {
           struct dirent **namelist;
           int n;
           n = scandir(".", &namelist, NULL, alphasort);
           if (n == -1) {
               perror("scandir");
               exit(EXIT_FAILURE);
           }
           while (n--) {
               printf("%s\n", namelist[n]->d_name);
               free(namelist[n]);   //------------------------>①每访问完一条目录或文件信息,释放由malloc分配的用于存放该信息的动态内存
           }
           free(namelist);  //------------------------>②访问完指定目录下所有目录或文件信息内容,释放malloc分配的用于索引的指针数组内存
           exit(EXIT_SUCCESS);
       }

排序函数:alphasort和versionsort

alphasort

int alphasort(const struct dirent **a, const struct dirent **b);

alphasort()的实现是把dirent的名称用strcoll()进行比较。

versionsort

int versionsort(const struct dirent **a, const struct dirent **b);

versionsort()的实现是把dirent的名称用strverscmp()进行比较。

排序函数的不同点

  • alphasort()的实现是把dirent的名称用strcoll()进行比较,排序的结果是按ASCII编码的值由小到大排序。
  • versionsort()的实现是把dirent的名称strverscmp()进行比较,排序的结果是也按ASCII编码的值由小到大排序,不同的是支持对名称中按数字序号的排序。

返回值

alphasort() 和 versionsort() 函数返回一个小于、等于或大于零的整数,当第一个参数被认为是小于、等于或大于第二个参数时.

总结

在本文中,我们详细介绍了Linux系统中用于目录扫描的几个重要函数。这些函数不仅在文件系统操作中有广泛应用,也是理解Linux系统编程的关键。

正如古人所说:“探索无止境,学无止境。”在编程的世界里,每一个函数、每一个接口都是一个新世界,值得我们去探索和理解。

结语

在我们的编程学习之旅中,理解是我们迈向更高层次的重要一步。然而,掌握新技能、新理念,始终需要时间和坚持。从心理学的角度看,学习往往伴随着不断的试错和调整,这就像是我们的大脑在逐渐优化其解决问题的“算法”。

这就是为什么当我们遇到错误,我们应该将其视为学习和进步的机会,而不仅仅是困扰。通过理解和解决这些问题,我们不仅可以修复当前的代码,更可以提升我们的编程能力,防止在未来的项目中犯相同的错误。

我鼓励大家积极参与进来,不断提升自己的编程技术。无论你是初学者还是有经验的开发者,我希望我的博客能对你的学习之路有所帮助。如果你觉得这篇文章有用,不妨点击收藏,或者留下你的评论分享你的见解和经验,也欢迎你对我博客的内容提出建议和问题。每一次的点赞、评论、分享和关注都是对我的最大支持,也是对我持续分享和创作的动力。

目录
相关文章
|
1月前
|
存储 Linux
Linux 目录名称
Linux系统目录结构简介:根目录(/)下包含各类功能目录,如/bin存放用户命令,/etc存储配置文件,/home为用户主目录,/var记录日志等可变数据,/usr存放用户工具,/tmp用于临时文件。各目录分工明确,保障系统有序运行。(238字)
204 5
|
6月前
|
安全 算法 Ubuntu
Linux(openssl)环境:编程控制让证书自签的技巧。
总结:在Linux环境中,OpenSSL是一个非常实用的工具,可以帮助我们轻松地生成自签名证书。通过上述三个简单步骤,即可为内部网络、测试环境或开发环境创建自签名证书。但在公共访问场景下,建议购买经过权威认证机构签发的证书,以避免安全警告。
305 13
|
7月前
|
Linux 定位技术
Linux系统中的cd命令:目录切换技巧
踏过千山,越过万水,人生就是一场不断前行的旅程,总充满了未知与挑战。然而,“cd”命令如同你的旅伴,会带你穿梭在如棋盘一般的文件系统中,探索每一处未知。希望你能从“cd”命令中找到乐趣,像是掌控了一种络新妙的魔法,去向未知进发,开始你的探索之旅。
312 24
|
8月前
|
监控 Linux
Linux基础:文件和目录类命令分析。
总的来说,这些基础命令,像是Linux中藏匿的小矮人,每一次我们使用他们,他们就把我们的指令准确的传递给Linux,让我们的指令变为现实。所以,现在就开始你的Linux之旅,挥动你的命令之剑,探索这个充满神秘而又奇妙的世界吧!
163 19
|
8月前
|
JavaScript Ubuntu Linux
如何在阿里云的linux上搭建Node.js编程环境?
本指南介绍如何在阿里云Linux服务器(Ubuntu/CentOS)上搭建Node.js环境,包含两种安装方式:包管理器快速安装和NVM多版本管理。同时覆盖全局npm工具配置、应用部署示例(如Express服务)、PM2持久化运行、阿里云安全组设置及外部访问验证等步骤,助你完成开发与生产环境的搭建。
|
8月前
|
Linux
Linux目录删除指南:彻底解决“Is a directory”错误
在 Linux 系统中遇到 `cannot remove &#39;xxx&#39;: Is a directory` 错误,是因为删除目录时未使用正确参数。解决方法包括:1) 使用 `rmdir` 删除空目录或 `rm -r` 删除非空目录;2) 检查并调整目录权限(如通过 `sudo` 提权);3) 处理特殊场景,例如文件属性异常、特殊字符或进程占用;4) 替代方法如 `find -delete` 或文件系统修复。操作前建议备份数据,并启用防误删功能(如 `alias rm=&#39;rm -i&#39;`)。掌握 `rm` 和 `rmdir` 的区别是关键。
742 1
|
消息中间件 存储 缓存
【嵌入式软件工程师面经】Linux系统编程(线程进程)
【嵌入式软件工程师面经】Linux系统编程(线程进程)
304 1
|
Linux 调度 数据库
Linux下的系统编程——线程同步(十三)
Linux下的系统编程——线程同步(十三)
254 0
Linux下的系统编程——线程同步(十三)
|
存储 Linux 调度
Linux系统编程 多线程基础
Linux系统编程 多线程基础
131 1
|
9月前
|
Linux
Linux编程: 在业务线程中注册和处理Linux信号
通过本文,您可以了解如何在业务线程中注册和处理Linux信号。正确处理信号可以提高程序的健壮性和稳定性。希望这些内容能帮助您更好地理解和应用Linux信号处理机制。
174 26