Skip to content

文件属性与目录 ​

Linux 系统中的文件类型 ​

在 Linux 系统下,并不会通过文件后缀名来识别一个文件的类型

普通文件 ​

       普通文件(regular file)在 Linux 系统下是最常见的,譬如文本文件、二进制文件,我们编写的源代码文件这些都是普通文件,也就是一般意义上的文件。 普通文件中的数据存在系统磁盘中,可以访问文件中的内容,文件中的内容以字节为单位进行存储于访问。

       普通文件可以分为两大类:文本文件和二进制文件

       stat 命令非常友好,会直观把文件类型显示出来;对于 ls 命令来说,并没有直观的显示出文件的类型,而是通过符号表示出来

目录文件 ​

       目录(directory) 就是文件夹,文件夹在 Linux 系统中也是一种文件,是一种特殊文件,同样我们也可以使用 vi 编辑器来打开文件夹

       文件夹中记录了该文件夹本省的路径以及该文件夹下所存放的文件。文件夹作为一种特殊文件,本身并不适合使用前面给大家介绍的文件 I/O 的方式来读写

字符设备文件和块设备文件 ​

       Linux 系统中,可将硬件设备分为字符设备和块设备,所以就有了字符设备文件和块设备文件两种文件类型。虽然有设备文件,但是设备文件并不对应磁盘上的一个文件,也就是说设备文件并不存在于磁盘中,而是由文件系统虚拟出来的,一般是由内存来维护, 当系统关机时,设备文件都会消失;

符号链接文件 ​

       符号链接文件(link) 类似于 Windows 系统中的快捷方式文件,是一种特殊文件,它的内容指向的是另一个文件路径,当对符号链接文件进行操作时,系统根据情况会对这个操作转移到它指向的文件上去,而不是对它本身进行操作

管道文件 ​

       管道文件(pipe) 主要用于进程间通信

套接字文件 ​

       套接字文件(socket)也是一种进程间通信的方式,与管道文件不同的是,它们可以在不同主机上的进程间通信,实际上就是网络通信

stat 函数 ​

       Linux 下可以使用 stat 命令查看文件的属性,其实这个命令内部就是通过调用 stat()函数来获取文件属性的, stat 函数是 Linux 中的系统调用,用于获取文件相关的信息

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

struct stat 结构体 ​

       struct stat 是内核定义的一个结构体,在<sys/stat.h>头文件中申明,所以可以在应用层使用,这个结构体中的所有元素加起来构成了文件的属性信息

c
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_mode 变量 ​

       st_mode 是 struct stat 结构体中的一个成员变量, 是一个 32 位无符号整形数据,该变量记录了文件的类型、文件的权限这些信息,其表示方法如下所示

O 对应的 3 个 bit 位用于描述其它用户的权限; G 对应的 3 个 bit 位用于描述同组用户的权限; U 对应的 3 个 bit 位用于描述文件所有者的权限; S 对应的 3 个 bit 位用于描述文件的特殊权限。

struct timespec 结构体 ​

       结构体定义在<time.h>头文件中, 是 Linux 系统中时间相关的结构体。应用程序中包含了<time.h>头文件, 就可以在应用程序中使用该结构体了

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

fstat 和 lstat 函数 ​

       stat 与 stat 区别在于, stat 是从文件名出发得到文件属性信息,不需要先打开文件;而 fstat 函数则是从文件描述符出发得到文件属性信息,所以使用 fstat 函数之前需要先打开文件得到文件描述符。

       lstat()与 stat、 fstat 的区别在于,对于符号链接文件, stat、 fstat 查阅的是符号链接文件所指向的文件对应的文件属性信息

文件属主 ​

       Linux 是一个多用户操作系统, 系统中一般存在着好几个不同的用户,而 Linux 系统中的每一个文件都有一个与之相关联的用户和用户组, 通过这个信息可以判断文件的所有者和所属组。        文件所有者表示该文件属于“谁”,也就是属于哪个用户。一般来说文件在创建时,其所有者就是创建该文件的那个用户。        文件所属组则表示该文件属于哪一个用户组。在 Linux 中,系统并不是通过用户名或用户组名来识别不同的用户和用户组,而是通过 ID。

有效用户 ID 和有效组 ID ​

       首先对于有效用户 ID 和有效组 ID 来说,这是进程所持有的概念,对于文件来说,并无此属性! 有效用户 ID 和有效组 ID 是站在操作系统的角度,用于给操作系统判断当前执行该进程的用户在当前环境下对某个文件是否拥有相应的权限        在 Linux 系统中,当进程对文件进行读写操作时,系统首先会判断该进程是否具有对该文件的读写权限,那如何判断呢?自然是通过该文件的权限位来判断        当进行权限检查时,并不是通过进程的实际用户和实际组来参与权限检查的,而是通过有效用户和有效组来参与文件权限检查。 通常, 绝大部分情况下,进程的有效用户等于实际用户

chown 函数 ​

       chown 是一个系统调用,该系统调用可用于改变文件的所有者(用户 ID)和所属组(组 ID) 。其实在Linux 系统下也有一 chown 命令,该命令的作用也是用于改变文件的所有者和所属组

bash
sudo chown root:root testApp.c

fchown 和 lchown 函数 ​

       这两个同样也是系统调用,作用与 chown 函数相同,只是参数、细节方面有些许同。

文件访问权限 ​

       struct stat 结构体中的 st_mode 字段记录了文件的访问权限位。当提及到文件时,指的是前面给大家介绍的任何类型的文件,并不仅仅指的是普通文件;所有文件类型(目录、设备文件)都有访问权限

普通权限和特殊权限 ​

每个文件都有 9 个普通的访问权限位,可将它们分为 3 类,如下表:

       每一行打印信息中, 前面的一串字符串就描述了该文件的 9 个访问权限以及文件类型,譬如"-rwxrwxrx":

最前面的一个字符表示该文件的类型, " - "表示该文件是一个普通文件。
r 表示具有读权限;
w 表示具有写权限;
x 表示具有执行权限;
-表示无此权限。

       st_mode 字段中除了记录文件的 9 个普通权限之外,还记录了文件的 3 个特殊权限        S 字段三个 bit 位中,从高位到低位依次表示文件的 set-user-ID 位权限、 set-groupID 位权限以及 sticky 位权限

目录权限 ​

       删除文件、创建文件这些操作也是需要相应权限的,那这些权限又是从哪里获取的呢?答案就是目录。 目录(文件夹)在 Linux 系统下也是一种文件,拥有与普通文件相同的权限方案(S/U/G/O) ,只是这些权限的含义另有所指。

检查文件权限 access ​

       程序当中对文件进行相关操作之前,需要先检查执行进程的用户是否对该文件拥有相应的权限。那如何检查呢?可以使用 access 系统调用

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

修改文件权限 chmod ​

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

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

umask 函数 ​

       umask命令用于查看/设置权限掩码, 权限掩码主要用于对新建文件的权限进行屏蔽。权限掩码的表示方式与文件权限的表示方式相同, 但是需要去除特殊权限位, umask 不能对特殊权限位进行屏蔽

文件的时间属性 ​

       3 个文件的时间属性: 文件最后被访问的时间、 文件内容最后被修改的时间以及文件状态最后被改变的时间,分别记录在 struct stat 结构体的 st_atim、 st_mtim 以及st_ctim 变量中

utime()、 utimes()修改时间属性 ​

       文件的时间属性虽然会在我们对文件进行相关操作(譬如:读、写)的时候发生改变,但这些改变都是隐式、被动的发生改变,除此之外,还可以使用 Linux 系统提供的系统调用显式的修改文件的时间属性。

符号链接(软链接)与硬链接 ​

       在 Linux 系统中有两种链接文件,分为软链接(也叫符号链接)文件和硬链接文件,软链接文件也就是前面给大家的 Linux 系统下的七种文件类型之一,其作用类似于 Windows 下的快捷方式。那么硬链接文件又是什么呢?

硬链接: ln 源文件 链接文件
软链接: ln -s 源文件 链接文件

目录 ​

       目录(文件夹) 在 Linux 系统也是一种文件, 是一种特殊文件,同样可以使用前面给大家介绍 open、read 等这些系统调用以及 C 库函数对其进行操作,但是目录作为一种特殊文件,并不适合使用前面介绍的文件 I/O 方式进行读写等操作。

目录存储形式 ​

       目录在文件系统中的存储方式与常规文件类似,常规文件包括了 inode 节点以及文件内容数据存储块(block)

创建和删除目录 ​

       使用 open 函数可以创建一个普通文件,但不能用于创建目录文件,在 Linux 系统下,提供了专门用于创建目录 mkdir()以及删除目录 rmdir 相关的系统调用。

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

rmdir()用于删除一个目录

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

打开、 读取以及关闭目录 ​

       打开、读取、关闭一个普通文件可以使用 open()、 read()、 close(),而对于目录来说,可以使用 opendir()、readdir()和 closedir()来打开、读取以及关闭目录

进程的当前工作目录 ​

       Linux 下的每一个进程都有自己的当前工作目录(current working directory),当前工作目录是该进程解析、搜索相对路径名的起点(不是以" / "斜杆开头的绝对路径) 。 譬如,代码中调用 open 函数打开文件时,传入的文件路径使用相对路径方式进行表示, 那么该进程解析这个相对路径名时、 会以进程的当前工作目录作为参考目录。

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

删除文件 ​

       前面给大家介绍了如何删除一个目录,使用 rmdir()函数即可,显然该函数并不能删除一个普通文件,那如何删除一个普通文件呢?方法就是通过系统调用 unlink()或使用 C库函数 remove()。

文件重命名 ​

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