文件属性与目录-I.MX6U嵌入式Linux C应用编程学习笔记基于正点原子阿尔法开发板

news2024/12/30 2:32:24

文件属性与目录

在这里插入图片描述

1、七种文件类型

普通文件(regular file)

  • 普通文件中的数据存在系统磁盘中,可以访问文件中的内容,文件中的内容以字节为单位进行存储于访问。

    • 文本文件

      • ASCII 码字符

      • 常见的.c、.h、.sh、.txt 等
        这些都是文本文件

    • 二进制文件

      • .o 文件、.bin 文件等都是二进制文件

      • 数字

  • 通过 stat 命令或者 ls 命令来查看文件类型

    • 对于 ls 命令,其中第一个字符(’ - ')就用于表
      示文件的类型

    • ⚫ ’ - ':普通文件

    • ⚫ ’ d ':目录文件

    • ⚫ ’ c ':字符设备文件

    • ⚫ ’ b ':块设备文件

    • ⚫ ’ l ':符号链接文件

    • ⚫ ’ s ':套接字文件

    • ⚫ ’ p ':管道文件

目录(directory)

  • 就是文件夹,文件夹在 Linux 系统中也是一种文件,是一种特殊文件

    • 可以用vi编辑器来查看

    • 文件夹中记录了该文件夹本省的路径以及该文件夹下所存放的文件

字符设备(character)和块设备(block)

  • 设备文件(字符设备文件、块设备文件)对应的是硬件设备

  • Linux 系统中,可将硬件设备分为字符设备和块设备

  • 字符设备文件一般存放在 Linux 系统/dev/目录下,所以/dev 也称为虚拟文件系统 devfs

  • 设备文件并不对应磁盘上的一个文件,也就是说设备文件并不存在于磁盘中,而是由文件系统虚拟出来的,一般是由内存来维护,当系统关机时,设备文件都会消失

符号链接(link)

  • 类似于 Windows 系统中的快捷方式文件,是一种特殊文件,它的内容指向的是另一个文件路径

管道(pipe)

  • 主要用于进程间通信

套接字(socket)

  • 用于网络通信,它们可以在不同主机上的进程间通信

2、获取文件属性:stat函数

#include <sys/types.h>

#include <sys/stat.h>
#include <unistd.h>
int stat(const char *pathname, struct stat *buf);

  • pathname:用于指定一个需要查看属性的文件路径

  • buf:struct stat 类型指针,用于指向一个 struct stat 结构体变量。获取到的文件属性信息就记录在 struct stat 结构体中

  • 返回值:成功返回 0;失败返回-1,并设置 error

struct stat结构体

  • struct stat 是内核定义的一个结构体,在<sys/stat.h>头文件中申明,所以可以在应用层使用

  • 这个结构体中的所有元素加起来构成了文件的属性信息

  • struct stat
    {

dev_t st_dev; /* 文件所在设备的 ID /
ino_t st_ino; /
文件对应 inode 节点编号 /
mode_t st_mode; /
文件对应的模式 /
nlink_t st_nlink; /
文件的链接数 /
uid_t st_uid; /
文件所有者的用户 ID /
gid_t st_gid; /
文件所有者的组 ID /
dev_t st_rdev; /
设备号(指针对设备文件) /
off_t st_size; /
文件大小(以字节为单位) /
blksize_t st_blksize; /
文件内容存储的块大小 /
blkcnt_t st_blocks; /
文件内容所占块数 */

struct timespec st_atim; /* 文件最后被访问的时间 /
struct timespec st_mtim; /
文件内容最后被修改的时间 /
struct timespec st_ctim; /
文件状态最后被改变的时间 */
}

- st_dev:该字段用于描述此文件所在的设备。不常用,可以不用理会。

- st_ino:文件的 inode 编号

- st_mode:该字段用于描述文件的模式,譬如文件类型、文件权限都记录在该变量中

- 用于记录文件的硬链接数,也就是为该文件创建了多少个硬链接文件。链接文件可以分为软链接(符号链接)文件和硬链接文件

- st_uid、st_gid:此两个字段分别用于描述文件所有者的用户  ID 以及文件所有者的组  ID

- st_rdev:该字段记录了设备号,设备号只针对于设备文件

- st_size:该字段记录了文件的大小(逻辑大小),以字节为单位

st_mode变量

  • struct stat 结构体中的一个成员变量

  • 32 位无符号整形数据

  • 记录了文件的类型、文件的权限

    • O 对应的 3 个 bit 位用于描述其它用户的权限

    • G 对应的 3 个 bit 位用于描述同组用户的权限

    • U 对应的 3 个 bit 位用于描述文件所有者的权限

    • S 对应的 3 个 bit 位用于描述文件的特殊权限

struct timespec结构体

  • 定义在<time.h>头文件中

  • struct timespec
    {
    time_t tv_sec; /* 秒 /
    syscall_slong_t tv_nsec; /
    纳秒 */
    };

    • time_t 其实指的就是 long int 类型

    • time_t 时间指的是一个时间段,从某一个时间点到某一个时间点所经过的秒数

    • time_t 时间在 Linux下被称为日历时间

  • 时间可以精确到纳秒

  • 通过 localtime()/localtime_r()或者 strftime()来得到更利于我们查看的时间表达方式

    • 2020-10-10 18:30:30

3、fstat 和 lstat 函数

除了 stat 函数之外,fstat 和 lstat 两个系统调用也可以获取文件属性信息。fstat、lstat 与 stat 的作用一样

fstat 函数

  • #include <sys/types.h>
    #include <sys/stat.h>
    #include <unistd.h>
    int fstat(int fd, struct stat *buf);

    • fd 表示文件描述符

    • buf:struct stat 类型指针,用于指向一个 struct stat 结构体变量。获取到的文件属性信息就记录在 struct stat 结构体中

    • 返回值:成功返回 0;失败返回-1,并设置 error

lstat 函数

  • 对于符号链接文件,stat、fstat 查阅的是符号链接文件所指向的文件对应的文件属性信息,而 lstat 查阅的是符号链接文件本身的属性信息

  • #include <sys/types.h>
    #include <sys/stat.h>
    #include <unistd.h>
    int lstat(const char *pathname, struct stat *buf);

    • pathname:用于指定一个需要查看属性的文件路径

    • buf:struct stat 类型指针,用于指向一个 struct stat 结构体变量。获取到的文件属性信息就记录在 struct stat 结构体中

    • 返回值:成功返回 0;失败返回-1,并设置 error

4、文件属主

用户和用户组

  • 文件所有者表示该文件属于“谁”,也就是属于哪个用户

  • 文件所属组则表示该文件属于哪一个用户组

  • 系统通过ID来识别不同的用户和用户组

  • 使用 ls 命令或 stat 命令便可以查看到文件的所有者和所属组

用户 ID(UID)组 ID(GID)

  • 文件的用户 ID 和组 ID 分别由 struct stat 结构体中的 st_uid 和 st_gid 所指定

  • 与一个进程相关联的 ID 有 5 个或更多

    • 实际用户ID

    • 实际组ID

    • 绝大部分情况下,进程的有效用户等于实际用户(有效用户 ID 等于实际用户 ID),有效组等于实际组(有效组 ID 等于实际组 ID)

    • 有效用户ID

    • 有效组ID

    • 附属组 ID

chown()函数

  • 改变文件的所有者(用户 ID)和所属组(组 ID)

  • 系统调用函数

    • 可通过"man 2 chown"命令查看
  • Linux 系统下也有一个 chown 命令,该命令的作用也是用于改变文件的所有者和所属组

    • 这个命令内部其实就是调用了 chown 函数来实现功能的
  • #include <unistd.h>
    int chown(const char *pathname, uid_t owner, gid_t group);

    • pathname:用于指定一个需要修改所有者和所属组的文件路径。

    • owner:将文件的所有者修改为该参数指定的用户(以用户 ID 的形式描述)

    • group:将文件的所属组修改为该参数指定的用户组(以用户组 ID 的形式描述)

    • 返回值:成功返回 0;失败将返回-1,并且会设置 errno

  • 两个限制条件

    • 只有超级用户进程能更改文件的用户 ID

    • 普通用户进程可以将文件的组 ID 修改为其所从属的任意附属组 ID,前提条件是该进程的有效用户 ID 等于文件的用户 ID;而超级用户进程可以将文件的组 ID 修改为任意值

fchown()和lchown()函数

  • 系统调用

  • 作用与 chown 函数相同,只是参数、细节方面有些许不同

  • int fchown(int fd, uid_t owner, gid_t group);

  • int lchown(const char *pathname, uid_t owner, gid_t group);

5、文件访问权限

普通权限和特殊权限(也可称为附加权限)

  • 每个文件都有 9 个普通的访问权限位

    • 使用 ls 命令或 stat 命令可以查看到文件的这 9 个访问权限

  • st_mode 字段中除了记录文件的 9 个普通权限之外,还记录了文件的 3 个特殊权限

    • S_ISUID 04000 set-user-ID bit
      S_ISGID 02000 set-group-ID bit (see below)
      S_ISVTX 01000 sticky bit (see below)

    • 例如当进程对文件进行操作的时候、将进行权限检查,如果文件的 set-user-ID 位权限被设置,内核会将进程的有效 ID 设置为该文件的用户 ID(文件所有者 ID),意味着该进程直接获取了文件所有者的权限、以文件所有者的身份操作该文件。

    • Linux 系统下绝大部分的文件都没有设置 set-user-ID 位权限和 set-group-ID 位权限,所以通常情况下, 进程的有效用户等于实际用户(有效用户 ID 等于实际用户 ID),有效组等于实际组(有效组 ID 等于实际组 ID)

目录权限

  • 删除文件、创建文件这些操作也是需要相应权限

  • 目录的读权限:可列出(譬如:通过 ls 命令)目录之下的内容(即目录下有哪些文件)

  • 目录的写权限:可以在目录下创建文件、删除文件

  • 目录的执行权限:可访问目录下的文件,譬如对目录下的文件进行读、写、执行等操作

权限检查:access()函数

  • 文件的权限检查不单单只讨论文件本身的权限,还需要涉及到文件所在目录的权限,只有同时都满足了,才能通过操作系统的权限检查,进而才可以对文件进行相关操作。那么程序当中对文件进行相关操作之前,需要使用 access 系统调用先检查执行进程的用户是否对该文件拥有相应的权限

  • #include <unistd.h>
    int access(const char *pathname, int mode);

    • pathname:需要进行权限检查的文件路径

    • mode

      • F_OK:检查文件是否存在

      • R_OK:检查是否拥有读权限

      • W_OK:检查是否拥有写权限

      • X_OK:检查是否拥有执行权限

      • 除了可以单独使用之外,还可以通过按位或运算符" | "组合在一起

    • 返回值:检查项通过则返回 0,表示拥有相应的权限并且文件存在;否则返回-1,如果多个检查项组合在一起,只要其中任何一项不通过都会返回-1。

权限修改:chmod()函数

  • 在 Linux 系统下,可以使用 chmod 命令修改文件权限,该命令内部实现方法其实是调用了 chmod 函数

  • chmod 函数是一个系统调用

  • #include <sys/stat.h>
    int chmod(const char *pathname, mode_t mode);

    • pathname:需要进行权限修改的文件路径,若该参数所指为符号链接,实际改变权限的文件是符号链接所指向的文件,而不是符号链接文件本身

    • mode:该参数用于描述文件权限,与 open 函数的第三个参数一样

      • O—这 3 个 bit 位用于表示其他用户的权限

      • G—这 3 个 bit 位用于表示同组用户(group)的权限,即与文件所有者有相同组 ID 的所有用户

      • U—这 3 个 bit 位用于表示文件所属用户的权限,即文件或目录的所属者

      • S—这 3 个 bit 位用于表示文件的特殊权限

    • 返回值:成功返回 0;失败返回-1,并设置 errno

  • 文件权限对于文件来说是非常重要的属性,是不能随随便便被任何用户所修改的,要想更改文件权限,要么是超级用户(root)进程、要么进程有效用户 ID 与文件的用户 ID(文件所有者)相匹配

  • fchmod 函数

    • 功能与 chmod 一样,参数略有不同。fchmod()与 chmod()的区别在于使用了文件描述符来代替文件路径,就像是 fstat 与 stat 的区别

    • #include <sys/stat.h>
      int fchmod(int fd, mode_t mode);

      • 使用了文件描述符 fd 代替了文件路径 pathname,其它功能都是一样的

umask

  • 在 Linux 下有一个 umask 命令,用于查看/设置权限掩码

  • umask 权限掩码是进程的一种属性,用于指明该进程新建文件或目录时,应屏蔽哪些权限位。进程的umask 通常继承至其父进程,譬如在 Ubuntu shell
    终端下执行的应用程序,它的 umask 继承至该 shell 进程

  • umask 不能对特殊权限位进行屏蔽

  • 文件实际的权限并不等于我们所设置的权限

    • mode & ~umask
  • 该函数是一个系统调用

  • #include <sys/types.h>
    #include <sys/stat.h>
    mode_t umask(mode_t mask);

    • mask:需要设置的权限掩码值,可以发现 make 参数的类型与 open 函数、chmod 函数中的 mode 参数对应的类型一样,所以其表示方式也是一样的

      • O—这 3 个 bit 位用于表示其他用户的权限

      • G—这 3 个 bit 位用于表示同组用户(group)的权限,即与文件所有者有相同组 ID 的所有用户

      • U—这 3 个 bit 位用于表示文件所属用户的权限,即文件或目录的所属者

      • S—这 3 个 bit 位用于表示文件的特殊权限

    • 返回值:返回设置之前的 umask 值,也就是旧的 umask

6、文件的时间戳

三个时间属性:st_atim、st_mtim 以及 st_ctim

- 状态更改指的是该文件的 inode 节点最后一次被修改的时间

- 有些操作并不仅仅只会影响文件本身的时间属性,还会影响到其父目录的相关时间属性

	-  

修改时间属性:utime()和utimes()

  • 系统调用

  • 显式的修改文件的时间属性

    • 只能显式修改文件的最后一次访问时间和文件内容最后被修改的时间,不能显式修改文件状态最后被改变的时间
  • #include <sys/types.h>
    #include <utime.h>
    int utime(const char *filename, const struct utimbuf *times);

    • filename:需要修改时间属性的文件路径

    • times:将时间属性修改为该参数所指定的时间值,times 是一个 struct utimbuf 结构体类型的指针,稍后给大家介绍,如果将 times 参数设置为 NULL,则会将文件的访问时间和修改时间设置为系统当前时间

      • struct utimbuf {
        time_t actime; /* 访问时间 /
        time_t modtime; /
        内容修改时间 */
        };

        • time_t 类型其实就是 long int 类型,所以这两个时间是以秒为单位的
    • 返回值:成功返回值 0;失败将返回-1,并会设置 errno

  • #include <sys/time.h>
    int utimes(const char *filename, const struct timeval times[2]);

    • utimes()与 utime()最大的区别在于前者可以以微秒级精度来指定时间值

    • filename:需要修改时间属性的文件路径

    • times 是一个 struct timeval 结构体类型的数组

      • struct timeval {
        long tv_sec; /* 秒 /
        long tv_usec; /
        微秒 */
        }
    • 返回值:成功返回 0;失败返回-1,并且会设置 errno

修改时间属性:futimens()和utimensat()

  • 系统调用

  • 显式修改文件时间戳

    • 只能显式修改文件的最后一次访问时间和文件内容最后被修改的时间,不能显式修改文件状态最后被改变的时间
  • 相对于 utime 和 utimes 函数有以下三个优点

    • 可按纳秒级精度设置时间戳

    • 可单独设置某一时间戳。譬如,只设置访问时间、而修改时间保持不变

    • 可独立将任一时间戳设置为当前时间

  • 使用 futimens()函数 , 需 要 先 将 文 件 打 开 , 通 过 文 件 描 述 符 进 行 操 作 , utimensat()可 以 直 接 使 用 文 件 路 径 方 式 进 行 操 作

  • #include <fcntl.h>
    #include <sys/stat.h>
    int futimens(int fd, const struct timespec times[2]);

    • fd:文件描述符

      • 使用 futimens()设置文件时间戳,需要先打开文件获取到文件描述符
    • times:将时间属性修改为该参数所指定的时间值,times 指向拥有 2 个 struct timespec 结构体类型变量的数组

    • 返回值:成功返回 0;失败将返回-1,并设置 errno

    • 该函数的时间戳可以按下列 4 种方式之一进行指定

      • 如果 times 参数是一个空指针,也就是 NULL,则表示将访问时间和修改时间都设置为当前时间

      • 如果 times 参数指向两个 struct timespec 结构体类型变量的数组,任一数组元素的 tv_nsec 字段的值设置为 UTIME_NOW,则表示相应的时间戳设置为当前时间,此时忽略相应的 tv_sec 字段

      • 如果 times 参数指向两个 struct timespec 结构体类型变量的数组,任一数组元素的 tv_nsec 字段的值设置为 UTIME_OMIT,则表示相应的时间戳保持不变,此时忽略 tv_sec 字段

      • 如果 times 参 数 指 向 两个 struct timespec 结 构 体类 型 变 量 的 数 组 ,且 tv_nsec 字 段 的 值 既 不是
        UTIME_NOW 也不是 UTIME_OMIT,在这种情况下,相应的时间戳设置为相应的 tv_sec 和 tv_nsec
        字段指定的值

    • 使用 futimens()函数只有以下进程,可对文件时间戳进行修改

      • 超级用户进程

      • 在参数 times 等于 NULL 的情况下,对文件拥有写权限的进程

      • 有效用户 ID 与该文件用户 ID(文件所有者)相匹配的进程

  • #include <fcntl.h>
    #include <sys/stat.h>
    int utimensat(int dirfd, const char *pathname, const struct timespec times[2], int flags);

    • dirfd:该参数可以是一个目录的文件描述符,也可以是特殊值 AT_FDCWD;如果 pathname 参数指定的是文件的绝对路径,则此参数会被忽略

    • pathname:指定文件路径。如果 pathname 参数指定的是一个相对路径

      • dirfd 参数不等于特殊值
        AT_FDCWD

        • 实际操作的文件路径是相对于文件描述符 dirfd 指向的目录进行解析
      • dirfd 参数等于特殊值 AT_FDCWD

        • 实际操作的文件路径是相对于调用进程的当前工作目录进行解析
    • times:将时间属性修改为该参数所指定的时间值,times 指向拥有 2 个 struct timespec 结构体类型变量的数组

    • flags : 此参数可以为 0 , 也可以设置为 AT_SYMLINK_NOFOLLOW

      • 如 果 设 置 为
        AT_SYMLINK_NOFOLLOW,当 pathname 参数指定的文件是符号链接,则修改的是该符号链接的时间戳,而不是它所指向的文件
    • 返回值:成功返回 0;失败返回-1、并会设置时间戳

7、符号链接

软链接与硬链接

  • 软链接文件也是 Linux 系统下的七种文件类型之一,其作用类似于 Windows 下的快捷方式

    • 软链接文件与源文件有着不同的 inode 号,所以也就是意味着它们之间有着不同的数据块

    • 软链接文件的数据块中存储的是源文件的路径名,链接文件可以通过这个路径找到被链接的源文件

      • 它们之间类似于一种“主从”关系,当源文件被删除之后,软链接文件依然存在,但此时它指向的是一个无效的文件路径,这种链接文件被称为悬空链接
    • inode 节点中记录的链接数并未将软链接计算在内

  • 从使用角度来讲,软链接与硬链接没有任何区别,都与正常的文件访问方式一样,支持读、写以及执行

  • 使用 ln 命令可以为一个文件创建软链接文件或硬链接文件,用法如下:
    硬链接:ln 源文件 链接文件
    软链接:ln -s 源文件 链接文件
    关于该命令其它用法,可以查看 man 手册

    • 使用 ln 命令创建的两个硬链接文件与源文件都拥有相同的 inode 号

    • 如果删除了硬链接文件或源文件其中之一,那文件所对应的 inode 以及文件内容在磁盘中的数据块不会被文件系统回收

      • 因为inode 数据结结构中会记录文件的硬链接数,struct stat 结构体中的st_nlink 成员变量就记录了文件的链接数

      • 只有当硬链接文件和源文件都被删除,inode 节点和对应的数据块才会被文件系统回收

    • struct stat 结构体中的st_nlink 成员变量就记录了文件的链接数,使用stat命令也可以查看

  • 硬链接的限制

    • 不能对目录创建硬链接(超级用户可以创建,但必须在底层文件系统支持的情况下)

    • 硬链接通常要求链接文件和源文件位于同一文件系统中

  • 软链接的优势

    • 可以对目录创建软链接

    • 可以跨越不同文件系统

    • 可以对不存在的文件创建软链接

创建硬链接:link()

  • 系统调用函数

  • #include <unistd.h>
    int link(const char *oldpath, const char *newpath);

    • oldpath:用于指定被链接的源文件路径,应避免 oldpath 参数指定为软链接文件,为软链接文件创建硬链接没有意义,虽然并不会报错

    • newpath:用于指定硬链接文件路径,如果 newpath 指定的文件路径已存在,则会产生错误

    • 返回值:成功返回 0;失败将返回-1,并且会设置 errno

创建软链接:symlink()

  • 系统调用函数

  • #include <unistd.h>
    int symlink(const char *target, const char *linkpath);

    • target:用于指定被链接的源文件路径,target 参数指定的也可以是一个软链接文件

      • 如果文件不存在,那么创建的软链接将成为“悬空链接”
    • linkpath:用于指定硬链接文件路径,如果 linkpath 指定的文件路径已存在,则会产生错误

    • 返回值:成功返回 0;失败将返回-1,并会设置 errno

读取软链接:readlink()

  • 使用 read 函数之前,需要先 open 打开该文件得到文件描述符,但是调用 open 打开一个链接文件本身是不会成功的,因为打开的并不是链接文件本身、而是其指向的文件,所以不能使用 read 来读取

  • 使用系统调用 readlink

  • #include <unistd.h>
    ssize_t readlink(const char *pathname, char *buf, size_t bufsiz);

    • pathname:需要读取的软链接文件路径。只能是软链接文件路径,不能是其它类型文件,否则调用函数将报错

    • buf:用于存放路径信息的缓冲区

    • bufsiz:读取大小,一般读取的大小需要大于链接文件数据块中存储的文件路径信息字节大小

    • 返回值:失败将返回-1,并会设置 errno;成功将返回读取到的字节数

8、目录

目录的存储形式

  • 由 inode 节点和目录块所构成,目录块当中记录了有哪些文件组织在这个目录下,记录它们的文件名以及对应的 inode 编号

  • 普通文件与目录

    • 普通文件由 inode 节点和数据块构成

    • 目录由 inode 节点和目录块构成

创建和删除目录:mkdir()、rmdir()

  • #include <sys/stat.h>
    #include <sys/types.h>
    int mkdir(const char *pathname, mode_t mode);

    • pathname:需要创建的目录路径

      • 该路径名可以是相对路径,也可以是绝对路径,若指定的路径名已经存在,则调用 mkdir()将会失败
    • mode:新建目录的权限设置,设置方式与 open 函数的 mode 参数一样,最终权限为(mode & ~umask)

      • 目录拥有与普通文件相同的权限位,但是其表示的含义与普通文件却有不同,权限的含义另有所指

        • 目录的读权限:可列出(譬如:通过 ls 命令)目录之下的内容(即目录下有哪些文件)

        • 目录的写权限:可以在目录下创建文件、删除文件

        • 目录的执行权限:可访问目录下的文件,譬如对目录下的文件进行读、写、执行等操作

    • 返回值:成功返回 0;失败将返回-1,并会设置 errno

  • #include <unistd.h>
    int rmdir(const char *pathname);

    • pathname

      • 删除的目录对应的路径名

      • 该目录必须是一个空目录,也就是该目录下只有.(当前目录)和…(上一级目录)这两个目录项

      • 指定的路径名不能是软链接文件,即使该链接文件指向了一个空目录

    • 返回值

      • 成功返回 0;失败将返回-1,并会设置 errno

打开、读取以及关闭目录:opendir()、readdir()、closedir()

  • C 库函数

  • #include <sys/types.h>
    #include <dirent.h>
    DIR *opendir(const char *name);

    • 用于打开一个目录,并返回指向该目录的句柄,供后续操作使用

    • name:指定需要打开的目录路径名,可以是绝对路径,也可以是相对路径

    • 返回值:成功将返回指向该目录的句柄,一个 DIR 指针(其实质是一个结构体指针),其作用类似于open 函数返回的文件描述符 fd,后续对该目录的操作需要使用该 DIR 指针变量;若调用失败,则返回 NULL

  • #include <dirent.h>
    struct dirent *readdir(DIR *dirp);

    • 用于读取目录,获取目录下所有文件的名称以及对应 inode 号,(事实上 Linux 系统还提供了一个 readdir 系统调用)

    • dirp:目录句柄 DIR 指针

    • 返回值:返回一个指向 struct dirent 结构体的指针,该结构体表示 dirp 指向的目录流中的下一个目录条目。在到达目录流的末尾或发生错误时,它返回 NULL

      • 对于目录这种特殊文件来说,这里将目录块中存储的数据称为目录流,存储了一个一个的目录项(目录条目)

      • struct dirent {
        ino_t d_ino; /* inode 编号 /
        off_t d_off; /
        not an offset; see NOTES /
        unsigned short d_reclen; /
        not an offset; see NOTES /
        unsigned char d_type; /
        type of file; not supported by all filesystem types */

char d_name[256]; /* 文件名 */
}

		- 我们需要关注  d_ino 和  d_name 两个字段即可,分别记录了文件的 inode 编号和文件名,其余字段并不是所有系统都支持

- 每次调用readdir()函数,都会从dirp所指向的目录流中读取下一条目录项(目录条目),并返回一个指向经静态分配而得的struct dirent结构体的指针。每次调用readdir()都会覆盖这个结构体。当遇到目录结尾或者出现错误时,readdir()会返回NULL。对于出错的情况,还会设置errno以表示具体的错误信息

- 使用readdir()函数返回的文件名并未按照任何特定顺序进行排序,而是按照文件在目录中出现的天然次序。这个天然次序取决于文件系统向目录添加文件时所遵循的顺序,以及在删除文件后对目录列表中空隙的填补方式。换句话说,readdir()返回的文件名顺序是由文件系统内部的管理方式决定的,而不是按照特定的排序规则。
  • #include <sys/types.h>
    #include <dirent.h>
    void rewinddir(DIR *dirp);

    • 将目录流重置为目录起点,以便对 readdir()的下一次调用将从目录列表中的
      第一个文件开始

    • dirp:目录句柄

    • 返回值:无返回值

  • #include <sys/types.h>
    #include <dirent.h>
    int closedir(DIR *dirp);

    • 关闭处于打开状态的目录,同时释放它所使用的资源

    • dirp:目录句柄

    • 返回值:成功返回 0;失败将返回-1,并设置 errno

进程的工作目录

  • Linux 下的每一个进程都有自己的当前工作目录(current working directory),当前工作目录是该进程解析、搜索相对路径名的起点(不是以" / "斜杆开头的绝对路径)

  • 运行一个进程时、其父进程的当前工作目录将被该进程所继承,成为该进程的当前工作目录

  • 通过 getcwd 函数来获取进程的当前工作目录

    • 系统调用

    • #include <unistd.h>
      char *getcwd(char *buf, size_t size);

      • buf:getcwd()将内含当前工作目录绝对路径的字符串存放在 buf 缓冲区中

      • size:缓冲区的大小,分配的缓冲区大小必须要大于字符串长度,否则调用将会失败

      • 返回值:如果调用成功将返回指向 buf 的指针,失败将返回 NULL,并设置 errno

    • 若传入的 buf 为 NULL,且 size 为 0,则 getcwd()内部会按需分配一个缓冲区,并将指向该缓冲区的指针作为函数的返回值,为了避免内存泄漏,调用者使用完之后必须调用 free()来释放这一缓冲区所占内存空间

  • 改变当前工作目录

    • 系统调用 chdir()和 fchdir()可以用于更改进程的当前工作目录

    • #include <unistd.h>
      int chdir(const char *path);
      int fchdir(int fd);

      • path:将进程的当前工作目录更改为 path 参数指定的目录,可以是绝对路径、也可以是相对路径,指定的目录必须要存在,否则会报错

      • fd:将进程的当前工作目录更改为 fd 文件描述符所指定的目录(譬如使用 open 函数打开一个目录)

      • 返回值:成功均返回 0;失败均返回-1,并设置 errno

9、删除文件与文件重命名操作

删除文件:unlink()、remove()

  • 通过系统调用 unlink()或使用 C 库函数 remove()删除一个普通文件

  • #include <unistd.h>
    int unlink(const char *pathname);

    • 用于移除/删除一个硬链接(从其父级目录下删除该目录条目)

      • 删除硬链接后,硬链接数就会减少,只有当硬链接数变为0的时候文件才会被删除
    • pathname:需要删除的文件路径,可使用相对路径、也可使用绝对路径,如果 pathname 参数指定的文件不存在,则调用 unlink()失败

      • 若 pathname 指定的文件为软链接文件,则删除软链接文件本身,而非软链接所指定的文件
    • 返回值:成功返回 0;失败将返回-1,并设置 errno

  • #include <stdio.h>
    int remove(const char *pathname);

    • 移除一个文件或空目录

    • pathname:需要删除的文件或目录路径,可以是相对路径、也可是决定路径

      • pathname 参数指定的是一个非目录文件,那么 remove()去调用 unlink(),如果 pathname 参数指定的是一个目录,那么 remove()去调用 rmdir()

      • pathname 参数指定的是一个软链接文件,则 remove()会删除链接文件本身、而非所指向的文件

    • 返回值:成功返回 0;失败将返回-1,并设置 errno

文件重命名:rename()

  • rename()既可以对文件进行重命名,又可以将文件移至同一文件系统中的另一个目录下

    • 调用rename()函数会将一个现有的路径名oldpath重命名为newpath参数所指定的路径名

    • rename()函数只操作目录条目,不会移动文件数据(不改变文件的inode编号,也不会移动文件数据块中存储的内容)

  • #include <stdio.h>
    int rename(const char *oldpath, const char *newpath);

    • oldpath:原文件路径

    • newpath:新文件路径

    • 返回值:成功返回 0;失败将返回-1,并设置 errno

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1655150.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

设计模式之单例模式详解

单例模式 描述&#xff1a;单例&#xff08;Singleton&#xff09;模式的定义&#xff1a;指一个类只有一个实例&#xff0c;且该类能自行创建这个实例的一种模式。 核心特点 单例类只有一个实例对象&#xff1b;该单例对象必须由单例类自行创建&#xff1b;单例类对外提供一…

Hive SQL-DML-insert插入数据

Hive SQL-DML-insert插入数据 1. 插入静态数据 可以直接插入具体的值到Hive表中&#xff1a; INSERT INTO TABLE tablename (column1, column2, column3) VALUES (value1, value2, value3),(value4, value5, value6),...;2. 插入查询结果 将一条查询的结果直接插入到另一个表中…

webpack从零到1 构建 vue3

为什么要手写webpack 不用cli &#xff08;无的放矢&#xff09;并不是 其实是为了加深我们对webpack 的了解方便以后灵活运用webpack 的技术 初始化项目结构&#xff08;跟cli 结构保持一致&#xff09; 新建 public src 等文件夹npm init -y 创建package.json文件tsc --init…

量化教程3---miniqmt当作第三方库设置,提供源代码

qmt提供了大qmt和miniqmt&#xff0c;大qmt在平台使用&#xff0c;miniqmt提供了交易的api和数据可以本地使用&#xff0c;非常的方便&#xff0c;合适自己开发大型的策略&#xff0c;本地还可以访问其他数据&#xff0c;网络等&#xff0c;也支持服务器 以前的教程 qmt教程1…

电脑怎么压缩视频?win端、Mac端压缩工具分享~

我们经常需要处理和分享视频文件。然而&#xff0c;视频文件往往会占用大量的存储空间&#xff0c;特别是高分辨率和高质量的视频。为了方便存储和分享&#xff0c;我们常常需要将视频文件进行压缩。本文将介绍如何使用电脑系统win端或Mac端自带的视频编辑器、以及常用的剪辑软…

树莓派配置双网卡分别为AD HOC和AP模式

树莓派配置双网卡分别为AD HOC和AP模式 需求说明&#xff1a;为了实现分级网络管理&#xff0c;将多个无人机分簇&#xff0c;簇间使用AD HOC进行无中心自组织的网络&#xff0c;簇内使用AP-AC模式进行中心化网络。因此&#xff0c;需要配置一台设备&#xff0c;同时完成AD HOC…

初识指针(3)<C语言>

前言 前面两篇文章已经介绍了一些关于指针的基础知识&#xff0c;下面我们可以涉及一些指针较容易混淆的概念&#xff0c;本篇文章将介绍数组名的理解、指针输入打印数组的不同格式、一维数组传参的本质&#xff0c;冒泡排序&#xff0c;二级指针&#xff0c;指针数组等。 数组…

【BST】Behavior Sequence Transformer for E-commerceRecommendation in Alibaba

一、提出背景 传统的Embedding&MLP模型结构将原始特征嵌入到低维向量中&#xff0c;然后将其concat后输入MLP进行最终推荐。DIN提出使用注意力机制来捕获候选项与用户先前点击的项之间的相似性。 然而&#xff0c;大多数这些工作只是连接不同的特征&#xff0c;而没有捕获用…

如何在您的域名中使用 Google Apps 创建 SPF 记录

关于 SPF 记录 SPF 记录是一种域名服务&#xff08;DNS&#xff09;记录&#xff0c;用于标识哪些邮件服务器被允许代表您的域发送电子邮件。它与在您的 DNS 区域中添加 MX 或 A 记录一样简单。 为什么它很重要&#xff1f; 如今&#xff0c;几乎所有滥用电子邮件消息都携带…

AMBA总线介绍

AMBA&#xff08;Advanced Microcontroller Bus Architecture&#xff09;是由ARM&#xff08;Advanced RISC Machines&#xff09;公司设计的一种高性能、高带宽的总线架构。AMBA总线广泛应用于各种嵌入式系统中&#xff0c;包括数字信号处理器、图形处理器、嵌入式处理器以及…

泽众财务RPA机器人常见五个应用场景

泽众RPA&#xff08;即机器人流程自动化&#xff0c;Robotic Process Automation, RPA&#xff09;解决方案是依托于各类先进信息技术手段的虚拟劳动力 &#xff08;数字劳动力&#xff09;&#xff0c;根据预先设定的程序操作指令对任务进行自动化处理&#xff0c;实现业务流程…

QGraphicsView实现简易地图11『指定层级-定位坐标』

前文链接&#xff1a;QGraphicsView实现简易地图10『自适应窗口大小』 提供一个地图初始化函数&#xff0c;指定地图显示的中心点和地图缩放层级 能够让地图显示某一层级的瓦片&#xff0c;并将中心点坐标显示在视图中心。 1、动态演示效果 7级地图-大连-老虎滩 定位到 8级地图…

【Shell】shell编程之条件语句

目录 一、条件测试操作 1.test命令 2.文件测试 3.整数值比较 4.字符串比较 5.逻辑测试 二、if语句的结构 1.单分支结构 2.双分支结构 3.多分支结构 三、case语句 总结 一、条件测试操作 1.test命令 测试表达式是否成立&#xff0c;若成立返回0&#xff0c;否则返回…

Apache DolphinScheduler 4月简报:社区发展与技术革新速递

各位热爱 DolphinScheduler 的小伙伴们&#xff0c;4 月份的 DolphinScheduler 社区月报更新啦&#xff01;这里将记录 DolphinScheduler 社区每月的重要更新&#xff0c;欢迎关注&#xff01; 月度 Merge 之星 感谢以下小伙伴 4 月为 Apache DolphinScheduler 所做的精彩贡献…

Graph RAG:基于知识图谱的检索增强技术与优势对比

身处信息爆炸时代&#xff0c;如何从海量信息中获取准确全面的搜索结果&#xff0c;并以更直观、可读的方式呈现出来是大家期待达成的目标。传统的搜索增强技术受限于训练文本数量、质量等问题&#xff0c;对于复杂或多义词查询效果不佳&#xff0c;更无法满足 ChatGPT 等大语言…

spark sql 与scala混合开发实现数据入mongodb

目录 概述资源解决问题效果环境配置相关包关键代码 测试测试结果 概述 在此提供 spark sql 与scala混合开发实现数据入mongodb 相关思路 将部分重复性功能进行通用化(使用SQL与Scala混合开发模式)。 相关组件 hadoop 3.3.6 spark 3.4.2 kyuubi 1.8.0 基于上术组件开发 资源 …

【笔试训练】day22

1.添加字符 求最少不相等的位数&#xff0c;可以先求最多相等的位数。 在添加字符之前&#xff0c;A和B最多相等的位数是多少&#xff1f;由于A后面可以添加字符&#xff0c;也就使得A字符可以在B的任意一个位置开始比较。遍历一遍这个比较的起点&#xff0c;从这个起点开始跟…

Angular中的路由

Angular中的路由 文章目录 Angular中的路由前言一、创建路由二、创建多个组件路由三、创建子路由四、创建多个组件子路由 前言 在Angular中&#xff0c;路由是用于在不同的视图和组件之间导航的机制。Angular提供了一种强大的路由机制来管理单页应用&#xff08;SPA&#xff0…

Npm Install Docusaurus Demo【npm 安装 docusaurus 实践 】

文章目录 1. 简介2. 前提2.1 安装 git2.2 安装 node 3. 安装4. 项目结构5. 访问5.1 localhost 访问5.2 ip 访问 1. 简介 Docusaurus 是一个facebook的开源项目&#xff0c;旨在帮助开发者构建易于维护和部署的文档网站。它提供了一个简单的方法来创建专业的文档网站&#xff0…

asp.net结课作业中遇到的问题解决3

目录 1、想实现不止鼠标滑过就显示图片&#xff0c;初始化状态下也可以显示图片&#xff0c;且每个图片还会自动变化&#xff0c;该如何实现 2、 同一个项目下的网页之间可以直接在地址栏输入跳转到阅读界面从而实现在这个跳转&#xff0c;那么如何防止这种现象呢&#xff1f;…