linux系统C/C++实现遍历指定目录

结构体简介

DIR结构体

struct __dirstream   
   {   
    void *__fd;    
    char *__data;    
    int __entry_data;    
    char *__ptr;    
    int __entry_ptr;    
    size_t __allocation;    
    size_t __size;    
    __libc_lock_define (, __lock)    
   };   
  
typedef struct __dirstream DIR;  

DIR结构体类似于FILE,是一个内部结构。函数

DIR *opendir(const char *pathname)	// 打开一个目录

即打开文件目录,返回的就是指向DIR结构体的指针,而该指针由以下几个函数使用:

struct dirent *readdir(DIR *dir);    // 返回参数 dir 目录流的下个目录进入点。
  
void rewinddir(DIR *dir);	// 设置参数dir目录流目前的读取位置为原来开头的读取位置
  
int closedir(DIR *dir);	// 关闭参数dir所指的目录流
  
long telldir(DIR *dir);	// 获取当前 dir 位置, 返回值代表距离目录文件开头的 偏移量
  
void seekdir(DIR *dir,long loc);	// 用来设置参数 dir 目录流当前的读取位置,在调用 readdir() 时便从此新位置开始读取。 参数loc代表距离目录文件开头的偏移量。

dirent 结构体

struct dirent   
{   
  long d_ino; /* inode number 索引节点号 */  
     
    off_t d_off; /* offset to this dirent 在目录文件中的偏移 */  
     
    unsigned short d_reclen; /* length of this d_name 文件名长 */  
     
    unsigned char d_type; /* the type of d_name 文件类型 */  
     
    char d_name [NAME_MAX+1]; /* file name (null-terminated) 文件名,最长255字符 */  
}  

dirent不仅仅指向目录,还指向目录中的具体文件,readdir函数同样也读取目录下的文件。linux下一切皆文件,目录其实也是一种文件。dirent结构体存储的关于文件的信息很少,获取更多信息需要用到stat函数

int stat(const char *file_name, struct stat *buf);

获取file_name的文件的详细信息,存储在stat结构体中

stat 结构体

struct stat {   
  
        mode_t     st_mode;       //文件访问权限   
  
        ino_t      st_ino;       //索引节点号   
  
        dev_t      st_dev;        //文件使用的设备号   
  
        dev_t      st_rdev;       //设备文件的设备号   
  
        nlink_t    st_nlink;      //文件的硬连接数   
  
        uid_t      st_uid;        //所有者用户识别号   
  
        gid_t      st_gid;        //组识别号   
  
        off_t      st_size;       //以字节为单位的文件容量   
  
        time_t     st_atime;      //最后一次访问该文件的时间   
  
        time_t     st_mtime;      //最后一次修改该文件的时间   
  
        time_t     st_ctime;      //最后一次改变该文件状态的时间   
  
        blksize_t st_blksize;    //包含该文件的磁盘块的大小   
  
        blkcnt_t   st_blocks;     //该文件所占的磁盘块   
  
      };  

d_type 文件类型

enum
{
    DT_UNKNOWN = 0,         //未知类型
# define DT_UNKNOWN DT_UNKNOWN
    DT_FIFO = 1,            //管道
# define DT_FIFO DT_FIFO
    DT_CHR = 2,             //字符设备
# define DT_CHR DT_CHR
    DT_DIR = 4,             //目录
# define DT_DIR DT_DIR
    DT_BLK = 6,             //块设备
# define DT_BLK DT_BLK
    DT_REG = 8,             //常规文件
# define DT_REG DT_REG
    DT_LNK = 10,            //符号链接
# define DT_LNK DT_LNK
    DT_SOCK = 12,           //套接字
# define DT_SOCK DT_SOCK
    DT_WHT = 14             //链接
# define DT_WHT DT_WHT
};

遍历并获取指定文件夹下文件详细信息

想要获取某目录下(比如a目下)文件的详细信息,可以写个函数getFiles:

  • 首先,使用opendir函数打开目录a返回指向目录a的DIR结构体b。

  • 接着,调用readdir( b)函数读取目录a下所有文件(包括目录),返回指向目录a下所有文件的dirent结构体c。

  • 然后,判断类型,是文件:调用stat(c->name,stat *d)来获取每个文件的详细信息,存储在stat结构体d中。是文件加:递归调用 getFiles。是其他情况:根据需要进行处理

代码示例:

GitHub: TraversingFilesInDirectory


#include <dirent.h>
#include <string>
#include <cstring>
#include <iostream>
#include <list>
#include <sys/stat.h>
#include <map>
#include <fstream>


void getFiles(const std::string& path, std::map<time_t,std::string,std::greater<time_t >> &filesMap)
{
    DIR *dir;
    struct dirent *ptr;

    if ((dir = opendir(path.c_str())) == nullptr)  /// 使用opendir函数打开目录a返回指向目录a的DIR结构体b。
    {
        perror("Open dir error...");
        exit(1);
    }

    // 确保路径最后有 /
    std::string newDir = path;
    char end = *(--newDir.end());  // 字符串最后一个字符
    if (end != '/') {
        newDir = newDir + "/";
    }

    // d_type表明该文件的类型:文件(8)、目录(4)、链接文件(10)
    while ((ptr = readdir(dir)) != nullptr) /// 调用readdir( b)函数读取目录a下所有文件(包括目录)
    {
        struct stat buff{};
        if (std::strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) {
            continue;
        } else if (ptr->d_type == 8) { // 文件(8)
            std::string fullPath = newDir + ptr->d_name;

            if (0==stat(fullPath.c_str(),&buff)) {
                time_t  time = buff.st_mtime; /// 最后一次修改文件的事件
                filesMap.insert(std::make_pair(time,fullPath));
            }
        } else if (ptr->d_type == 10) { // 链接文件(10)
            continue;
        } else if (ptr->d_type == 4) { // 目录(4)
            getFiles(newDir + ptr->d_name + "/", filesMap);
        }
    }
    closedir(dir);
}

int main ()
{
    std::string pathdir = "/home/leacock/CLionProjects";

    // 按time_t也就是key从大到小排列,也就是时间由近及远
    std::map<time_t,std::string,std::greater<time_t >> filesMap;
    filesMap.clear();
    getFiles(pathdir,filesMap);


    std::ofstream outfile("filesinfo.txt");


    auto iter = filesMap.begin();
    while(iter != filesMap.end()) {
        time_t time = iter->first;
        std::string filePath = iter->second;
        iter++;
        char buffer[255] = {0};
        tm *tm = localtime(&time);
        strftime(buffer, 80, "%Y-%m-%d %H:%M:%S", tm);
        std::string tmp = buffer;
        std::string msg;
        msg.append(buffer).append(" time = ").append(std::to_string(time)).append(" dirPath = ").append(filePath);
        std::cout << msg << std::endl;
        outfile << msg << std::endl;
    }
    outfile.close();
    return 0;
}
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

墨1024

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值