linux下基于c/c++遍历文件夹

头文件

#include <sys/types.h>  
#include <dirent.h>
#include <sys/stat.h>
#include <errno.h>

opendir()

该函数的作用是打开目录,将返回值传递给后续的操作函数,如readdir()

函数原型:DIR * opendir(const char * name);

该函接受一个字符串,即目录名,如果读取成功,则返回DIR类型的指针,否则返回NULL。
常见的错误代码如下:

错误码原因
EACCESS权限不足
EMFILE已达到进程可同时打开的文件数上限。
ENFILE已达到系统可同时打开的文件数上限。
ENOTDIR参数name非真正的目录
ENOENT参数name 指定的目录不存在,或是参数name 为一空字符串。
ENOMEM核心内存不足。

DIR是一个文件句柄,其定义如下:

struct __dirstream
 {
       int fd;                     /* File descriptor.  */
       __libc_lock_define (, lock) /* Mutex lock for this structure.  */
       size_t allocation;          /* Space allocated for the block.  */
       size_t size;                /* Total valid data in the block.  */
       size_t offset;              /* Current offset into the block.  */
       off_t filepos;              /* Position of next entry to read.  */
       /* Directory block.  */
       char data[0] __attribute__ ((aligned (__alignof__ (void*))));
   };

typedef struct __dirstream DIR;  // 声明在<dirent.h>中

__dirstream定义出处

readdir()

DIR结构体类似于FILE,是一个内部结构,这个句柄就是等一下要传给readdir()去遍历该目录,该函数的原型如下:

struct dirent *readdir(DIR *dir)

它接收一个DIR类型的指针,有错误发生或读取到目录文件尾则返回NULL,成功则返回下个目录进入点,为struct 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字符 */  
}  

其中d_type表明该文件的类型,预定义的宏及含义如下:

解释
DT_BLK(6)这是一个block device
DT_CHR(2)这是一个character device
DT_DIR(4)这是一个目录
DT_FIFO(1)这是一个命名管道(FIFO)
DT_LNK(10)这是一个符号链接
DT_REG(8)这是一个普通的文件
DT_SOCK(12)这是一个UNIX domain socket
DT_UNKNOWN(0)文件类型不确定

错误码errno

定义<errno.h>中的一个整型变量,当系统调用或者一些库函数出错,设置该变量以表明(最近)发生错误的原因,这里列举几种常用的错误码及解释:

解释
EPERM(1)操作不被允许
ENOENT文件或目录不存在
ESRCH进程不存在
EINTR系统调用中断
EIO输入或输出错误

linux中通过如下命令可以查看所有的错误码

sudo apt install moreutils
errno -l

部分输出如下:
在这里插入图片描述

stat()

从上述定义也能够看出来,dirent结构体存储的关于文件的信息很少,所以dirent同样也是起着一个索引的作用,如果想获得类似ls -l那种效果的文件信息,必须要靠stat函数了。
函数原型如下:

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

通过readdir()函数读取到的文件名存储在结构体dirent的d_name成员中,stat()的作用就是获取文件名为d_name的文件的详细信息,存储在stat结构体中,调用成功返回0,否则-1, errno指示了错误原因。以下为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;     //该文件所占的磁盘块   
      };  

closedir()

当遍历完目录后,就调用closedir()函数关闭它:

int closedir(DIR *dir);

关闭成功则返回0,失败返回-1,errno指示了错误原因。

代码示例

遍历文件目录,输出每个文件大小

# test.cpp
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<dirent.h>
#include<sys/stat.h>

void travel_dir(const char* path){
    DIR *d;
    struct dirent* file = new dirent();
    struct stat* st = new struct stat();
    if(!(d = opendir(path))){
        printf("erroe dirs %s!!!\n", path);
        return;
    }

    while((file = readdir(d)) != NULL){
        // 跳过隐藏文件, 当前目录(.),或上一级目录
        if(strncmp(file->d_name, ".", 1) == 0)
            continue;
        //如果是普通的文件
        if(file->d_type == 8){
            printf("%s\n", file->d_name);
            char* file_path = (char *)malloc(strlen(path) + strlen(file->d_name) + 2);
            memset(file_path, '\0', sizeof(file_path));
            strcat(file_path, path);
            strcat(file_path, "/");
            strcat(file_path, file->d_name);
            printf("%s\n", file_path);
            int num = stat(file_path, st);
            printf("%d\n", num);
            if(num == 0)
                printf("文件大小: %dByte\n", st->st_size);
            else{
                perror("stat");
            }
        }
        //如果是文件夹
        if(file->d_type == 4){
            char* dir_path = (char *)malloc(strlen(path) + strlen(file->d_name) + 2);
            memset(dir_path, '\0', sizeof(dir_path));
            strcat(dir_path, path);
            strcat(dir_path, "/");
            strcat(dir_path, file->d_name);
            printf("%s\n", dir_path);
            travel_dir(dir_path);
        }
    }
    closedir(d);
    return;
}

int main(int argc, char * argv[]){
    travel_dir(argv[1]);
    return 0;
}

执行

g++ test.cpp -o a.out
./a.out /home/lw/DIR

输出如下:
在这里插入图片描述

参考资料:
errno介绍
dirent.h
opendir()
readdir()
stat()

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值