文章目录
主要说明linux下,创建目录和列出目录中的文件两个功能, 使用场景最多
一. 获取当前目录
char *getcwd(char *buf, size_t size)
二.切换目录
int chdir(const char *path);
三. 目录的创建和删除
- 创建目录
int mkdir(const char *pathname, mode_t mode);
- mode : 就是目录的权限相关的, 可以固定为
00755
- mode : 就是目录的权限相关的, 可以固定为
- 删除目录
int rmdir(const char *pathname);
四. 获取目录中的文件列表
4.1 包含头文件
#include <dirent.h>
4.2 包含的库函数
- 打开目录的库函数
DIR *opendir(const char *pathname);
- 读取目录的库函数:
struct dirent *readdir(DIR *dirp);
- 关闭目录的函数:
int closedir(DIR, *dirp);
4.3 数据结构
DIR是目录指针,就像文件操作时的文件指针一样
调用一次readdir返回结构体struct dirent的指针, 只管用就行了,不用管怎么实现的.存放的是本次读取到的文件信息, 就像操作文件时调用一次fgets
时一样,不同的是,fgets
返回字符串, readdir
返回结构体.
struct dirent{
long d_ino; //inode number 索引节点号
off_t d_off; // offset to this dirent 在目录中的偏移
unsigned short d_name; // length of this d_name 文件名长
unsigned char d_type; // the type of d_name 文件类型
char d_name[NAME_MAX+a]; // file name 文件名,最长255字符
}
我们只关心d_type和d_name成员, 其它不关心
d_name: 是文件名,或目录名
d_type: 描述了文件的类型, 有多种取值, 常用的是8和4, 8-常规文件(A regular file), 4-目录文件(A directory), 其它的暂时不用管
上码明所有
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h> // readdir需要包含的头文件
#include <unistd.h>
int ReadDir(const char *strpathname); // 以递归方式获取目录中及其子目录中的文件,并打印出来
int MKDIR(const char *pathname); // 以递归方式创建目录
int main(){
char strcwd[301];
// 获取当前目录
memset(strcwd, 0, sizeof(strcwd));
getcwd(strcwd, sizeof(strcwd));
printf("=%s=\n", strcwd);
// 切换目录至'/home'
chdir("/home");
memset(strcwd, 0, sizeof(strcwd));
getcwd(strcwd, sizeof(strcwd));
printf("=%s=\n", strcwd);
// 创建目录和删除目录
mkdir("/home/hello/c", 00755);
rmdir("/home/hello/c");
// 以递归方式获取目录中的文件
ReadDir("/home/hello");
// 以递归方式创建目录
MKDIR("/home/hello/testc/test2c/test3c");
return 0;
}
int MKDIR(const char *pathname){
char strPathName[301];
int ii=0;
for(ii=1; ii<strlen(pathname); ii++){
if(pathname[ii]!='/') continue;
memset(strPathName, 0, sizeof(strPathName));
strncpy(strPathName, pathname, 1);
// 判断目录是否存在, 若存在,则返回0,不存在返回-1, 后面有讲到.
if(access(strPathName,F_OK)==0) continue;
if(mkdir(strPathName, 00755)!=0) return -1;
}
return 0;
}
int ReadDir(const char *strpathname){
// 获取目录中的文件
DIR *dir; // 定义目录指针
char strchdpath[256]; // 子目录的全路径
if ((dir=(opendir(strpathname))) ==0 ){
printf("打开目录失败");
return -1;
}
struct dirent *stdinfo; // 定义了一个结构指针, 用于存放从目录中读取到的文件和目录>的信息
while(1){
stdinfo=readdir(dir);
if(stdinfo==0) break; // 结束了,就跳出循环
if (strncmp(stdinfo->d_name, ".", 1)==0) continue; // 过滤以.开始的文件
// 若是常规文件, 就打印出来
if (stdinfo->d_type==8){
printf("文件名=%s, 文件类型=%d\n", stdinfo->d_name, stdinfo->d_type);
}
//若是目录文件, 就递归
if (stdinfo->d_type==4){
sprintf(strchdpath, "%s/%s", strpathname, stdinfo->d_name);
ReadDir(strchdpath);
}
}
closedir(dir); //关闭目录指针
return 0;
}
五. 补充一哈
5.1 access库函数
功能: 用于判断当前操作系统用户对文件或目录的存取权限
包含头文件: #include <unistd.h>
申明方式: int access(const char *pathname, int mode);
- pathname 文件名或目录名, 可以是当前目录的文件或目录,也可以是全路径(实际开发中,建议使用全路径)
- mode 需要判断的存取权限,在头文件<unistd.h>中的预定义如下:
- #define R_OK 4
// R_OK只判断是否有读权限
- #define W_OK 2
// W_OK只判断是否有写权限
- #define X_OK 1
// X_OK判断是否有执行权限
- #define F_OK 0
// F_OK只判断是否存在
返回值: 当pathname 满足mode时, 返回0, 不满足返回-1.
实际开发中, 主要用判断文件是否存在.
5.2 stat库函数
5.2.1 stat 结构体 用于存放文件的状态信息
struct stat {
dev_t st_dev; //device 文件的设备编号
ino_t st_ino; //inode 文件的i-node
mode_t st_mode; //protection 文件的类型和存取的权限, 开发中常用,取值很多,
nlink_t st_nlink; //numbers of hard links 连到该文件的硬连接数目, 刚建立的文件为1.
uid_t st_uid; // user ID of owner 文件所有者的用户识别码
gid_t st_gid; //gourp ID of owner 文件所有者的组识别码
dev_t st_rdev; //若此文件为装置设备文件, 则为其设备编号
off_t st_size; // total size, in bytes, 文件大小,以字节计算, 开发中, 常用.
unsigned long st_blksize; //blocksize of filesystem I/O, 文件系统的IO缓冲区大小
unsigned long st_blocks; //numbers of blocks allocated 占用文件区块的个数, 每一区域大小为512字节
time_t st_atime; //time of last access 文件最近一次被存取或执行的时间,一般只有在用mknod, utime, read, write, tructate时改变
time_t st_mtime; //time of last modification 文件最后一次被修改的时间,一般只有在用mknod, utime, write时改变, 实际开发中, 常用
time_t st_ctime; // time of last change i-node 最后一次被更改的时间, 此参数会在文件所有者, 组, 权限被更改时更新.
}
5.2.2 stat库函数
包含的头文件:
sys/types.h sys/stat.h unistd.h
申明:
int stat(const char* path, struct stat *buf)
stat函数获取path 指定文件或目录的信息, 并将 信息保存到结构体buf中,执行成功0, 失败返回-1.
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
int main(int argc, char *argv[]){
if (access(argv[1], F_OK) !=0){
printf("文件或目录%s 不存在\n", argv[1]);
return -1;
}
struct stat ststat;
if(stat(argv[1], &ststat)!=0) return -1;
if (S_ISREG(ststat.st_mode)) printf("%s 是一个文件\n", argv[1]);
if (S_ISDIR(ststat.st_mode)) printf("%s 是一个目录\n", argv[1]);
printf("filename=%s, mtime=%ld, size=%d\n", argv[1], ststat.st_mtime, ststat.st_size);
}
调用时, 要记得带个目录或文件的参数, 否则直接打印不存在. , 因为调用时, 在函数内部都是argv[1], 表示是第二个参数.
5.2.3 utime 库函数
功能: 用于修改文件的存取时间和更改时间
包含头文件: #include <utime.h>
申明: int utime(const char *filename, const struct utimbuf *times);
说明: utime()用来修改filename文件所属的inode存取时间. 如果参数times为空指针(NULL),则该文件的存取时间和更改时间全部会设为当前时间,结构体 utimbuf定义如下:
struct utimbuf {
time_t actime;
time_t modtime;
};
struct utimbuf stut;
strtotime("2021-05-01 10:10:10", &stut.actime);
strtotime("2021-05-01 10:10:10", &stut.modtime);
utime(filename, &stut);
5.2.4 rename 函数
用于重命名文件或目录, 相当于操作系统的mv命令, 实际开发过程中, 极少重命名目录, 重命名文件经常用到.
int rename(const char *oldpath, const char *newpath);
oldpath, 文件或目录的原名
newapth,文件或目录的新的名称
成功返回0, 失败返回-1
实际开发中, 经常会向一个文件中写入数据, 别人来读取数据, 但是, 当你正在写入时, 别人同时读取这个文件, 就会造成读到数据不完整.
解决办法: 就是在写入fopen("/d/aaa.txt", "w")
时, 在文件名后加个.tmp
, 即fopen("/d/aaa.txt.tmp", "w")
, 当文件close
后, 再使用rename("/d/aaa.txt.tmp", "/d/aaa.txt")
, 把.tmp
删除即可. 完美解决!!
5.2.5 remove 函数
删除文件或目录