跨平台文件操作dirent.h详解

LINUX下历遍目录的方法一般是这样的 :
打开目录->读取->关闭目录 
相关函数是 
opendir -> readdir -> closedir

#include <dirent.h>
DIR *opendir(const char *dirname);//打开目录,并返回句柄
struct dirent *readdir(DIR *dirp);//读取句柄,返回dirent结构体
int closedir(DIR *dirp);         //关闭句柄
telldir() //返回当前指针的位置,表示第几个元素
//dirent.h是用于目录操作的头文件,linux 默认在/usr/include目录下(会自动包含其他文件)

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;  

dirent结构体:

struct dirent
{
    long d_ino;                     
    off_t d_off;                    
    unsigned short d_reclen;        
    char d_name [NAME_MAX+1];       
};
  • d_ino存放的是该文件的索引节点号inode;
  • d_off 是文件在目录中的编移,具体是什么意思也不是很明白,很少用到它,
  • 基本上就是用到d_name
  • short d_reclen是这个文件的长度,需要注意的是这里的长度并不是指文件大小,因为大小和长度是两回回事了,你可以用lseek将文件长度移得很长,但大小其实还是那么大。
  • 最后一个元素就是我们要的了,文件名称。

使用dirent:

1.删除文件夹下所有文件

DIR *foder = opendir(file_path_to_delete.c_str());
    struct dirent *next_file;
    char filepath[256];

    while ((next_file = readdir(foder)) != NULL)
    {
        // build the path for each file in the folder
        sprintf(filepath, "%s/%s", course_path.c_str(), next_file->d_name);
        remove(filepath);
    }

注意: 
路径要以’/’结尾:

file_path_to_delete += "\/";

通过readdir函数读取到的文件名存储在结构体dirent的d_name成员中,而函数 
int stat(const char *file_name, struct stat *buf);的作用就是获取文件名为d_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;     //该文件所占的磁盘块   
}; 

返回说明:  
成功执行时,返回0。失败返回-1,errno被设为以下的某个值  
EBADF: 文件描述词无效
EFAULT: 地址空间不可访问
ELOOP: 遍历路径时遇到太多的符号连接
ENAMETOOLONG:文件路径名太长
ENOENT:路径名的部分组件不存在,或路径名是空字串
ENOMEM:内存不足
ENOTDIR:路径名的部分组件不是目录文件和目录

1.判断是文件还是目录:

 #include<iostream>
     int main(int argc,char* argv[])
     {
          int i;
          struct stat buf;
          char * ptr;
        for(i=1;i<argc;i++)
         {
            if(lstat(argv[i],&buf)<0)
               {
                 perror("错误原因是:");
                 continue;
               }
            if (S_ISREG(buf.st_mode))
                ptr="普通文件";
            if (S_ISDIR(buf.st_mode))
                ptr="目录";
    
           cout<<"参数为:"<<argv[i]<<"的标识是一个"<<ptr<<endl;
         }
        exit(0);
     }

解析:

文件类型:
普通文件---S_ISREG();    目录文件---S_ISDIR();   特殊的块设备文件---S_ISBLK();  字符特殊文件--S_ISCHR();   套接字(P O S I X . 1或S V R 4无此类型)---S_ISSOCK();  管道或FIFO---S_ISFIFO();  符号链接( P O S I X . 1或S V R 4无此类型)---S_ISLNK();

文件类型信息包含在stat结构的st_mode成员中,可以用如下的宏确定文件类型,这些宏是stat结构中的st_mode成员

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
};
#i nclude<sys/stat.h>
int stat(const char *restrict pathname,struct stat *restrict buf);
int fstat(int fields,struct stat *buf);
int lstat(const char *restrict pathname,struct stat *restrict buf);
返回值:若成功则返回0,失败则返回-1

一旦给出pathname,stat函数就返回与此命名文件有关的信息结构,fstat函数获取已在描述符fields上打开文件的有关信息。
lstat函数类似于stat.但是当命名的文件是一个符号链接时,lstat返回该符号链接的有关信息,而不是由该符号链接引用文件
的信息。第二个参数buf是指针,它指向一个我们必须提供的结构,这些函数填写由buf指向的结构。该结构的实际定义可能随实现
有所不同.

最后,总结一下,想要获取某目录下(比如a目下)b文件的详细信息,我们应该怎样做?

  1. 首先,我们使用opendir函数打开目录a,返回指向目录a的DIR结构体c。
  2. 接着,我们调用readdir( c)函数读取目录a下所有文件(包括目录),返回指向目录a下所有文件的dirent结构体d。
  3. 然后,我们遍历d,调用stat(d->name,stat *e)来获取每个文件的详细信息,存储在stat结构体e中。

2.判断目录是否存在:

 DIR *mydir = NULL;  
    if((mydir= opendir(dir))==NULL)//判断目录   
    {  
      int ret = mkdir(dir, MODE);//创建目录  MODE为创建目录是的模式
      if (ret != 0)  
      {  
          return -1;  
      }  
      printf("%s created sucess!/n", dir);  
    }  

关于mkdir

函数原型:

int mkdir(const char *pathname, mode_t mode);

函数说明:

mkdir()函数以mode方式创建一个以参数pathname命名的目录,mode定义新创建目录的权限。

返回值:

若目录创建成功,则返回0;否则返回-1,并将错误记录到全局变量errno中。

mode方式:

 
S_IRWXU 00700权限,代表该文件所有者拥有读,写和执行操作的权限
S_IRUSR(S_IREAD) 00400权限,代表该文件所有者拥有可读的权限
S_IWUSR(S_IWRITE) 00200权限,代表该文件所有者拥有可写的权限
S_IXUSR(S_IEXEC) 00100权限,代表该文件所有者拥有执行的权限
S_IRWXG 00070权限,代表该文件用户组拥有读,写和执行操作的权限
S_IRGRP 00040权限,代表该文件用户组拥有可读的权限
S_IWGRP 00020权限,代表该文件用户组拥有可写的权限
S_IXGRP 00010权限,代表该文件用户组拥有执行的权限
S_IRWXO 00007权限,代表其他用户拥有读,写和执行操作的权限
S_IROTH 00004权限,代表其他用户拥有可读的权限
S_IWOTH 00002权限,代表其他用户拥有可写的权限
S_IXOTH 00001权限,代表其他用户拥有执行的权限

1   用   int   access(const   char   *pathname,   int   mode);   判断有没有此文件或目录 --它区别不出这是文件还是目录
2   用   int   stat(const   char   *file_name,   struct   stat   *buf); 判断该文件或目录是否否存在 ;得到st_mode,然后判断是不是目录文件。 
    stat()系统调用看是否成功,不成功就不存在,成功判断返回的st_mode是否是一个文件夹。

********************************************************************
linux c关于目录是否存在,新建目录等操作
1. 创建目录

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

       int mkdir(const char *pathname, mode_t mode);

运用条件:只能在已存在的目录下建立一级子目录

返回值:  返回0表示成功,返回-1表述出错。

mode 表示新目录的权限,可以取以下值:

其中,mode就用0777,0755这种形式。

 
2. 判断一个目录是否存在

可以使用opendir来判断,这是比较简单的办法。

#include<stdio.h>
#include<string.h>
#include<errno.h>
 
#include<unistd.h>
 
#include<dirent.h>
#include<sys/types.h>
#include<sys/stat.h>
 
extern int errno;
 
#define MODE (S_IRWXU | S_IRWXG | S_IRWXO)
 
int mk_dir(char *dir)
{
    DIR *mydir = NULL;
    if((mydir= opendir(dir))==NULL)//判断目录 
    {
      int ret = mkdir(dir, MODE);//创建目录
      if (ret != 0)
      {
          return -1;
      }
      printf("%s created sucess!/n", dir);
    }
    else
    {
        printf("%s exist!/n", dir);
    }
 
    return 0;
}
 
int mk_all_dir(char *dir)
{
    bool flag = true;
    char *pDir = dir;
    while (flag)
    {
        char *pIndex = index(pDir, '/');
        if (pIndex != NULL && pIndex != dir)
        {
            char buffer[512] = {0};
            int msg_size = pIndex - dir;
            memcpy(buffer, dir, msg_size);
            int ret = mk_dir(buffer);
            if (ret < 0)
            {
                printf("%s created failed!/n", dir);
            }
        }
        else if (pIndex == NULL && pDir == dir)
        {
            printf("dir is not directory!/n");
            return -1;
        }
        else if (pIndex == NULL && pDir != dir)
        {
            int ret = mk_dir(dir);
            if (ret < 0)
            {
                printf("%s created failed!/n", dir);
            }
 
            break;
        }
 
        pDir = pIndex+1;
 
    }
 
    return 0;
}
 
 
 
int main()
{
    char buffer[512] = {0};
    printf("please input path mane/n");
    fgets(buffer, sizeof(buffer), stdin);
    
    char *pIndex = index(buffer, '/n');
    if (pIndex != NULL)
    {
        *pIndex = '/0';
    }
 
    printf("check path mane %s/n", buffer);
 
    int ret = mk_all_dir(buffer);
    if (ret < 0)
    {
        printf("% mkdir failed!/n", buffer);
        return -1;
    }
 
    return 0;
}

https://github.com/tronkko/dirent/blob/master/include/dirent.h

猜你喜欢

转载自www.cnblogs.com/tianzeng/p/9296214.html