文件io - 目录操作

说明

  • 在linux上一切皆文件,目录本质上也是一个文件,目录文件中按照固定的数据格式保存了该目录下的所有文件的信息列表。
  • 用户可以按照普通文件的操作方式去读写目录文件,但是需要按照特定的数据格式,linux提供的目录操作API就是隐藏了格式细节,使目录操作更简单。

基础操作

创建目录

#include <sys/stat.h>  
int mkdir(const char* path, mode_t mode);  
  • 函数说明: 创建一个空目录并设置访问权限为mode,成功返回0,失败-1。
  • 注意:
  1. 由于目录是一个文件,该函数单次调用只能创建一个目录,不能一次创建多层目录,如:“ A/B”,path可以为多层目录,创建的目录为最后一个子目录。
  2. 由于目录结构信息保存在目录文件中,创建目录只能一层一层创建,缺少一层将会创建失败,目录无法链接起来。

打开目录

#include <dirent.h>
DIR *opendir(const char *name);
  • 函数说明:opendir函数用来打开参数name指定的目录, 并返回DIR*形态的目录/文件流,和文件open()类似。
  • 返回值:成功则返回DIR*型态的目录流,打开失败则返回NULL,错误代码:
EACCESS  权限不足
EMFILE   已达到进程可同时打开的文件数上限
ENFILE   已达到系统可同时打开的文件数上限
ENOTDIR  参数name非真正的目录
ENOENT   参数name指定的目录不存在, 或是参数name为一空字符串
ENOMEM   核心内存不足

读取目录

#include <dirent.h>
struct dirent *readdir(DIR *dir);
  • 函数说明:readdir函数返回参数dir目录/文件流的下一个数据节点,节点数据结构dirent定义如下:
struct dirent{
ino_t d_ino;
ff_t d_off;
signed short int d_reclen;
unsigned char d_type;
char d_name[256];
};
d_ino    此目录进入点的inode
d_off    目录文件开头至此目录进入点的位移
d_reclen d_name的长度, 不包含NULL字符
d_type   d_name所指的文件类型
d_name   文件名
  • 返回值:成功则返回下个目录/文件节点,错误或读取到目录文件尾则返回NULL,返回EBADF表示参数dir为无效的目录流.
  • 示例
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>

int main(void)
{
    DIR *dir;
    struct dirent *ptr;
    int i;
    dir = opendir("/etc/rc.d");
    while((ptr = readdir(dir)) != NULL)
    {
        printf("d_name: %s\n", ptr->d_name);
    }
    
    return 0;
}
* 运行结果:
d_name: rc1.d
d_name: rc
d_name: rc.sysinit
d_name: ..
d_name: rc6.d
d_name: rc4.d
d_name: . 

目录过滤/排序

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

1. dirp:指定的文件夹扫描路径。
2. namelist:过滤/排序后的结果数据。
3. filter: 过滤函数指针,为NULL则不过滤。
4. compar:排序函数指针,为NULL则不排序。
  • 函数说明:scandir函数扫描dirp目录下(不包含其子目录,子目录是独立的文件)满足filter过滤模式的文件,返回的结果是经过compare函数排序的,保存在namelist中;当函数成功执行时返回找到匹配模式文件的个数,如果失败将返回-1。
  • 注意:返回结果namelist是通过malloc动态分配内存的,使用后需要手动释放内存。
  • 系统中已定义了两个排序函数
  1. alphasort: 按ASCLL码值从小到大排序。
  2. versionsort:使用需要加上语句 #define _GNU_SOURCE,并且使用gcc编译,暂时不知其排序规则,测试结果和alphasort一样。

自定义过滤和排序函数

  1. 过滤函数
int Filter(const struct dirent* d)       
{                                         
    if(isdigit(d->d_name[0])) //文件名的第一个字符是否是数字
    {                                      
        return 1;                
    }                                      
    return 0;  
} 
  • 返回不为0表示采纳,返回0将被过滤掉。
  1. 排序函数
  • man中说明,根据返回值表示小于,等于,大于,以此进行排序。
The alphasort() and versionsort() functions return an integer less than, equal to, or greater than zero if the first argument is considered to be respectively less than, equal to, or greater than the second.

使用

  • 示例
#include <dirent.h>
int main()
{
    struct dirent **namelist;
    int n;
    n = scandir(".", &namelist, 0, alphasort);
    if (n < 0)
       perror("scandir");
    else
    {
       while(n--)
       {
           printf("%s\n", namelist[n]->d_name);
           free(namelist[n]);
       }
       free(namelist);
    }
}
  • 使用该函数需要注意一些问题,如下:
  1. 内存问题;该函数自己申请内存存储文件信息,不像readdir逐个处理,文件较多时占用过多内存。
  2. 性能问题;如果你只是需要满足过滤条件并且排好序的文件列表中的前几个,该函数每次执行都会处理所有文件。

目录流操作

  • 由于目录本身也是一个文件,所以可以像文件一样获取操作偏移值。
  1. 获取目录流的偏移
#include <dirent.h>
off_t telldir(DIR *dir);
  1. 设置读取目录的位置
#include <dirent.h>
void seekdir(DIR * dir, off_t offset);
  1. 设置读取位置为目录起始位置
#include <dirent.h>
void  rewinddir(DIR *dp);
  • 以上函数使用和文件流操作是类似的,示例如下:
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>

int main()
{
    DIR * dir;
    struct dirent * ptr;
    int offset, offset_5, i = 0;
    
    dir = opendir("/etc/rc.d");
    while((ptr = readdir(dir)) != NULL)
    {
        offset = telldir(dir); //获取偏移
        if(++i == 5)
            offset_5 = offset;
        printf("d_name : %s offset :%d \n", ptr->d_name, offset);
    }
    seekdir(dir, offset_5); //设置偏移
    printf("Readdir again!\n");
    
    while((ptr = readdir(dir)) != NULL)
    {
        offset = telldir(dir);
        printf("d_name : %s offset :%d\n", ptr->d_name, offset);
    }
    closedir(dir);
}

关闭目录流

#include <dirent.h>
int closedir(DIR*dp);
  • 关闭成功则返回0,,失败返回-1。

删除目录

#include <unistd.h>  
int rmdir(const char* pathname);
  • 函数说明:删除一个空目录,删除非空目录会返回失败,需要先删除其中的文件和目录,因为目录也是一个文件,删除非空目录,其中的文件就成了野文件,无法访问了,链接缺少了。
  • 返回值:成功返回0,失败-1;
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值