初学C语言之目录操作

2023-05-16

文章目录

  • 一. 获取当前目录
  • 二.切换目录
  • 三. 目录的创建和删除
  • 四. 获取目录中的文件列表
    • 4.1 包含头文件
    • 4.2 包含的库函数
    • 4.3 数据结构
  • 五. 补充一哈
    • 5.1 access库函数
    • 5.2 stat库函数
      • 5.2.1 stat 结构体 用于存放文件的状态信息
      • 5.2.2 stat库函数
      • 5.2.3 utime 库函数
      • 5.2.4 rename 函数
      • 5.2.5 remove 函数

主要说明linux下,创建目录和列出目录中的文件两个功能, 使用场景最多

一. 获取当前目录

char *getcwd(char *buf, size_t size)

二.切换目录

int chdir(const char *path);

三. 目录的创建和删除

  1. 创建目录 int mkdir(const char *pathname, mode_t mode);
    • mode : 就是目录的权限相关的, 可以固定为00755
  2. 删除目录 int rmdir(const char *pathname);

四. 获取目录中的文件列表

4.1 包含头文件

#include <dirent.h>

4.2 包含的库函数

  1. 打开目录的库函数 DIR *opendir(const char *pathname);
  2. 读取目录的库函数: struct dirent *readdir(DIR *dirp);
  3. 关闭目录的函数: 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 函数

删除文件或目录

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

初学C语言之目录操作 的相关文章

随机推荐