linux目录编程:DIR,stat, dirent结构体解析与应用

来源:互联网 发布:软件自动升级程序 编辑:程序博客网 时间:2024/05/21 06:28

    在Linux中,“一切都是文件”。对文本文件编程我应用的比较多,但是对目录文件的操作涉及的比较少。在对目录编程中,会用到DIR,stat, dirent这些结构体,下面就介绍他们的一些基本信息和应用实例。

DIR 结构

DIR 类似于 FILE ,是一个内部结构体,定义如下:

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;
常用的操作函数有:
struct dirent *readdir(DIR *dp); /* 返回参数dp目录流的下个目录进入点*/
void rewinddir(DIR *dp);  /* 把目录指针恢复到目录的起始位置 */
int  closedir(DIR *dp); /* 关闭参数dp所指的目录流 */
long telldir(DIR *dp);/* 获取当前dp位置 返回目录流dp的当前位置,此返回值代表距离目录文件开头的偏移量,有错误发生时返回-1 */

void seekdir(DIR *dp, long loc); /* 用来设置参数dp目录流当前的读取位置,在调用readdir()时便从此新位置开始读取。参数loc代表距离目录文件开头的偏移量 */



stat 结构
struct stat {    dev_t         st_dev;              //文件的设备编号    ino_t         st_ino;               //节点    mode_t        st_mode;      //文件的类型和存取的权限    nlink_t       st_nlink;           //连到该文件的硬连接数目,刚建立的文件值为1    uid_t         st_uid;              //用户ID    gid_t         st_gid;              //组ID    dev_t         st_rdev;            //(设备类型)若此文件为设备文件,则为其设备编号    off_t         st_size;              //文件字节数(文件大小)    unsigned long st_blksize;   //块大小(文件系统的I/O 缓冲区大小)    unsigned long st_blocks;    //块数    time_t        st_atime;      //最后一次访问时间    time_t        st_mtime;     //最后一次修改时间    time_t        st_ctime;      //最后一次改变时间(指属性)};
上面结构体中的st_mode 在POSIX中定义了检查这些类型的宏定义:
    S_ISLNK (st_mode)    判断是否为符号连接
    S_ISREG (st_mode)    是否为一般文件
    S_ISDIR (st_mode)    是否为目录
    S_ISCHR (st_mode)    是否为字符装置文件
    S_ISBLK (st_mode)    是否为块设备
    S_ISSOCK(st_mode)    是否为socket

stat函数讲解

表头文件:   

         #include <sys/stat.h>

         #include <unistd.h>

定义函数:    int stat(const char *file_name, struct stat *buf);
函数说明:    通过文件名filename获取文件信息,并保存在buf所指的结构体stat中
返回值:      执行成功则返回0,失败返回-1,错误代码存于errno

错误代码:
    ENOENT         参数file_name指定的文件不存在
    ENOTDIR        路径中的目录存在但却非真正的目录
    ELOOP          欲打开的文件有过多符号连接问题,上限为16符号连接
    EFAULT         参数buf为无效指针,指向无法存在的内存空间
    EACCESS        存取文件时被拒绝
    ENOMEM         核心内存不足
    ENAMETOOLONG   参数file_name的路径名称太长

相关函数:
int stat(const char *restrict pathname, struct stat *restrict buf);

提供文件名字,获取文件对应属性。

int fstat(int filedes, struct stat *buf);
通过文件描述符获取文件对应的属性。
int lstat(const char *restrict pathname, struct stat *restrict buf);

连接文件名字,获取文件属性。


stat与lstat的区别:

    对于链接文件,stat 获取到的是链接文件指向文件的文件信息, lstat获取到的是连接文件本身的信息。

stat与fstat的区别:

    stat 输入的是文件的名字,fstat 输入的是文件描述符。


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结构体的内容不多,它主要的作用是起到索引的作用。要获取文件的主要信息,需要与stat结合使用。


应用实例:

#include <unistd.h>#include <stdio.h>#include <dirent.h>#include <string.h>#include <sys/stat.h>#include <stdlib.h>/* 递归调用,输出目录下所有目录及文件*/void printdir(char *dir, int depth){DIR *dp;struct dirent *entry;struct stat statbuf;/* 打开目录 */if ((dp = opendir(dir)) == NULL) {fprintf(stderr, "Can`t open directory %s\n", dir);return ;}/* 切换目录 */chdir(dir);/* 返回目录流下个目录的进入点 */while ((entry = readdir(dp)) != NULL) {lstat(entry->d_name, &statbuf);/* 判断是否为目录*/if (S_ISDIR(statbuf.st_mode)) {/* 如果是 . 或.. 目录,结束该次循环 */if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0 ){continue;}/* %*s  这里 * 被depth 代替,做标准输出最小长度控制,输出目录名 */printf("%*s%s/\n", depth, "", entry->d_name);/* 递归调用 */printdir(entry->d_name, depth+4);} else{/* 输出文件名 */printf("%*s%s\n", depth, "", entry->d_name);}}/* 切换到目录 .. */chdir("..");/* 关闭目录 */closedir(dp);}int main(int argc, char *argv[]){    char *topdir = ".";      if (argc >= 2){ topdir = argv[1];}       printf("Directory scan of %s\n", topdir);printdir(topdir, 0);printf("done.\n");exit(0);}
当前目录结构如下:

biao@ubuntu:~/test/file$ lsa.out  dir_test.c  testbiao@ubuntu:~/test/file$ tree.├── a.out├── dir_test.c└── test    ├── test    ├── test1    │   ├── test    │   └── test2    │       ├── test2    │       └── test3    │           └── test3    ├── test1_1    │   └── test1_1    └── test1_2        └── test1_26 directories, 8 filesbiao@ubuntu:~/test/file$ 
执行结果如下:

biao@ubuntu:~/test/file$ biao@ubuntu:~/test/file$ lsa.out  dir_test.c  testbiao@ubuntu:~/test/file$ ./a.out Directory scan of .dir_test.ca.outtest/    test1/        test        test2/            test3/                test3            test2    test    test1_2/        test1_2    test1_1/        test1_1done.biao@ubuntu:~/test/file$ 




原创粉丝点击