文件IO——目录操作
目录
- 前言
- 一、基本概念
- 二、创建目录
- 三、删除目录
- 四、打开目录
- 五、进入目录
- 六、读取目录
- 七、练习
- 1.
- 代码实现
- 2.
- 1.代码实现
- 2.代码实现
前言
之前设计的程序只能访问某个路径下的某个文件,如果打算一次访问某个路径下的多个不同类型的文件,就需要用户手动调用open函数实现,但是当文件数量较多时,这种方案并不能满足需求,那请问是否有比较轻松高效的方式来实现访问某个路径下的多个不同类型的文件呢?当然是有的,在Linux系统下一切皆文件,目录在Linux系统下也属于文件类型之一,可以通过系统IO来进行访问,常见的访问目录的接口有:opendir、readdir、chdir、mkdir、rmdir、remove、getcwd、rewindir等。
一、基本概念
在Linux系统下目录是一种特殊的文件,只不过目录存储的数据的最小单位并不是字符,而是目录项,所以目录与普通文件又有所区别,另外,Linux文件系统下目录和文件夹的含义也并不相同,目录的本质是索引,文件夹的本质是容器。
也就是说,目录是用来保存项目的索引,而不用保存项目本身。Linux 和 UNIX 中的目录并不保存它里面的文件。它们只是记录文件位置的信息。
举个例子:目录和文件夹的区别就相当于门牌号和房子的区别,房子里面可以住人或者存放物品,而门牌号只是记录房子所在的位置,方便用户寻找和访问。
可以看到,在 Linux 或 Unix 操作系统中所有的文件和目录都被组织成以一个根节点开始的倒置的树状结构。
Linux系统的文件系统的最顶层是由根目录开始的,使用 / 来表示根目录。在根目录之下的既可以是目录,也可以是文件,而每一个目录中又可以包含子目录文件。如此反复就可以构成一个庞大的文件系统。
二、创建目录
Linux系统提供了一个用于创建目录的mkdir函数接口,第一个参数pathname指的是目录的路径,第二个参数mode用来指定新目录的模式。
三、删除目录
Linux系统提供了一个用于删除空目录的rmdir函数接口,第一个参数pathname指的是待删除目录的路径。
四、打开目录
Linux系统提供了一个用于打开目录的opendir函数接口,第一个参数pathname指的是待打开目录的路径。
五、进入目录
另外,打开目录并不意味着进入目录,而获取目录里面的文件的信息必须要先进入目录,可以用函数 chdir() 进入目录。
六、读取目录
Linux系统提供了一个用于读取目录的readdir函数接口,第一个参数dirp指的是待读取目录的目录指针。函数成功返回一个指向该目录中下一个目录项的指针,失败返回NULL。
Linux系统提供了一个用于获取文件信息的stat函数接口,第一个参数path指的是待读取文件的路径,第二个参数指的是获取的文件信息结构体的地址。
七、练习
1.
设计程序,利用操作目录的函数接口实现读取某个路径下的目录并把该目录下的所有文件名称输出到终端。并且要求目录路径作为main函数参数的形式传递。
代码实现
/** Copyright (c)* * date: 2025-7-27* * author: Charles* * function name : ReadDir.c** function: 读取当前文件夹中的信息*/#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>int main(int argc, char const *argv[])
{if(argc != 2){perror("argumen is invaild!\n");exit(-1);}//打开目录DIR* dir = opendir(argv[1]);if(!dir){perror("opendir failed!\n");exit(-1);}struct dirent *dirset;//读目录下每个文件的信息while(1){dirset = readdir(dir);if(!dirset){break;}if(dirset->d_type != DT_REG || dirset->d_name[0] == '.'){continue;}printf("%ld %c [%s]\n", dirset->d_ino, dirset->d_type,dirset->d_name);}return 0;
}
2.
设计程序利用访问目录的函数接口实现获取某个目录中所有文件的名称,并利用stat函数把每个获取的文件的类型输出到终端。 提示:可以参考man手册关于stat函数的例程。
1.代码实现
/** Copyright (c)* * date: 2025-7-27* * author: Charles* * function name : ReadDir.c** function: 读取当前目录每个文件的信息*/#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>const char* get_file_type(mode_t mode){if(S_ISREG(mode)) return "普通文件";if (S_ISDIR(mode)) return "目录";if (S_ISCHR(mode)) return "字符设备";if (S_ISBLK(mode)) return "块设备";if (S_ISFIFO(mode)) return "管道(FIFO)";if (S_ISLNK(mode)) return "符号链接";if (S_ISSOCK(mode)) return "套接字";return "未知类型";
}int main(int argc, char const *argv[])
{if(argc != 2){perror("argumen is invaild!\n");exit(-1);}const char* dir_path = argv[1];printf("扫描目录: %s\n", dir_path);printf("%-30s %-15s %-15s %s\n", "文件名", "类型", "大小(字节)", "最后修改时间");printf("--------------------------------------------------------------------\n");//打开文件DIR* dir = opendir(dir_path);if(!dir){perror("opendir 失败");return -1;}//定义变量struct dirent *entry;struct stat statbuf;char file_path[1024];int cnt = 0;//读取目录信息while((entry = readdir(dir))){if(strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue;//构建文件路径snprintf(file_path, sizeof(file_path), "%s/%s", dir_path, entry->d_name);//调用stat函数获取信息if(0 != stat(file_path, &statbuf)){printf("获取信息失败 %s",file_path);continue;}char time[80];strftime(time, sizeof(time), "%Y-%m-%d %H:%M:%S", localtime(&statbuf.st_mtime));printf("%-30s %-15s %-15ld %s\n", entry->d_name, get_file_type(statbuf.st_mode), statbuf.st_size, time);cnt++;}printf("总共扫描到 %d 个文件\n", cnt);closedir(dir);return 0;
}
2.代码实现
这个代码是手册里面的案例
#include <sys/types.h>
#include <sys/stat.h>
#include <stdint.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/sysmacros.h>int main(int argc, char *argv[]){struct stat sb;if (argc != 2) {fprintf(stderr, "Usage: %s <pathname>\n", argv[0]);exit(EXIT_FAILURE);}if (lstat(argv[1], &sb) == -1) {perror("lstat");exit(EXIT_FAILURE);}printf("ID of containing device: [%jx,%jx]\n",(uintmax_t) major(sb.st_dev),(uintmax_t) minor(sb.st_dev));printf("File type: ");switch (sb.st_mode & S_IFMT) {case S_IFBLK: printf("block device\n"); break;case S_IFCHR: printf("character device\n"); break;case S_IFDIR: printf("directory\n"); break;case S_IFIFO: printf("FIFO/pipe\n"); break;case S_IFLNK: printf("symlink\n"); break;case S_IFREG: printf("regular file\n"); break;case S_IFSOCK: printf("socket\n"); break;default: printf("unknown?\n"); break;}printf("I-node number: %ju\n", (uintmax_t) sb.st_ino);printf("Mode: %jo (octal)\n",(uintmax_t) sb.st_mode);printf("Link count: %ju\n", (uintmax_t) sb.st_nlink);printf("Ownership: UID=%ju GID=%ju\n",(uintmax_t) sb.st_uid, (uintmax_t) sb.st_gid);printf("Preferred I/O block size: %jd bytes\n",(intmax_t) sb.st_blksize);printf("File size: %jd bytes\n",(intmax_t) sb.st_size);printf("Blocks allocated: %jd\n",(intmax_t) sb.st_blocks);printf("Last status change: %s", ctime(&sb.st_ctime));printf("Last file access: %s", ctime(&sb.st_atime));printf("Last file modification: %s", ctime(&sb.st_mtime));exit(EXIT_SUCCESS);}
希望各位靓仔靓女点赞,收藏,关注多多支持,我们共同进步,后续我会更新更多的面试真题,你们的支持将是我前进最大的动力。