结构体简介
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;
}