前言承接上一篇文件高级操作内容本篇深入 Linux 文件系统底层从文件属性获取、inode 本质、目录遍历到权限管理逐层拆解。理解这些内容才能真正搞懂 Linux “一切皆文件” 的设计底层掌握软硬链接、目录扫描、权限控制等工程高频操作同时也是笔试面试中文件系统原理题的核心考点。一、文件属性获取stat 函数族1. 三个核心 stat 函数Linux 提供了三个函数用于获取文件属性核心区别在于打开方式和对软链接的处理#include sys/types.h #include sys/stat.h #include unistd.h int stat(const char *pathname, struct stat *buf); int fstat(int fd, struct stat *buf); int lstat(const char *pathname, struct stat *buf);函数入参形式软链接处理stat文件路径跟随软链接返回链接指向的目标文件属性fstat文件描述符已打开的文件直接获取属性lstat文件路径不跟随软链接返回软链接自身的属性面试高频考点区分 stat 和 lstat 的核心差异。判断一个文件是不是软链接必须用 lstat用 stat 永远只能得到目标文件的类型。2. stat 结构体核心成员struct stat是存储文件属性的核心结构体最常用的成员如下struct stat { ino_t st_ino; // inode编号 mode_t st_mode; // 文件类型与权限 nlink_t st_nlink; // 硬链接数 uid_t st_uid; // 所有者用户ID gid_t st_gid; // 所属组ID off_t st_size; // 文件大小字节 time_t st_atime; // 最后访问时间 time_t st_mtime; // 最后修改时间 time_t st_ctime; // 最后属性修改时间 blksize_t st_blksize; // IO块大小 blkcnt_t st_blocks; // 占用的磁盘块数 };3. 文件类型与权限判断st_mode是一个整型高位存储文件类型低位存储权限。标准提供了专门的宏来判断不需要手动位运算。文件类型判断宏S_ISREG(m)普通文件S_ISDIR(m)目录文件S_ISLNK(m)软链接文件S_ISCHR(m)字符设备文件S_ISBLK(m)块设备文件S_ISFIFO(m)管道文件S_ISSOCK(m)套接字文件权限位掩码S_IRUSR所有者读权限0400S_IWUSR所有者写权限0200S_IXUSR所有者执行权限0100S_IRGRP、S_IWGRP、S_IXGRP所属组权限S_IROTH、S_IWOTH、S_IXOTH其他用户权限4. 实战获取并打印文件属性#include stdio.h #include sys/stat.h #include unistd.h #include time.h int main(int argc, char *argv[]) { if (argc ! 2) { fprintf(stderr, 用法%s 文件名\n, argv[0]); return 1; } struct stat st; if (lstat(argv[1], st) -1) { perror(lstat failed); return 1; } printf(inode编号%ld\n, (long)st.st_ino); printf(文件大小%ld 字节\n, (long)st.st_size); printf(硬链接数%ld\n, (long)st.st_nlink); // 判断文件类型 printf(文件类型); if (S_ISREG(st.st_mode)) printf(普通文件\n); else if (S_ISDIR(st.st_mode)) printf(目录\n); else if (S_ISLNK(st.st_mode)) printf(软链接\n); else printf(其他类型\n); printf(最后修改时间%s, ctime(st.st_mtime)); return 0; }二、inode文件系统的核心本质1. 什么是 inodeinode索引节点是 Linux 文件系统的核心数据结构每个文件对应唯一的 inode用于存储文件的元数据信息文件的权限、所有者、大小、时间戳等属性也就是 stat 结构体里的大部分内容文件数据块的存储位置指针硬链接计数核心结论文件名不是文件的本质inode 才是文件的唯一标识。文件名只是方便人类记忆的别名目录本质上就是一张 “文件名→inode 号” 的映射表。2. 硬链接的本质硬链接就是多个文件名指向同一个 inode共享同一份文件数据。创建硬链接后inode 的硬链接计数 1删除一个硬链接计数 - 1只有计数减到 0 时文件才真正被删除硬链接不能跨文件系统不能给目录创建硬链接3. 文件删除的底层逻辑调用unlink删除一个文件时内核做两件事删除目录中对应的文件名映射inode 的硬链接计数减 1 只有当硬链接计数为 0且没有进程打开该文件时文件的数据块才会被真正释放。这也是为什么程序打开的文件即使被 rm 删除磁盘空间也不会立刻释放直到进程关闭文件。三、目录操作目录遍历实现1. 核心目录操作函数Linux 通过目录流的方式操作目录核心函数有三个#include dirent.h DIR *opendir(const char *name); struct dirent *readdir(DIR *dirp); int closedir(DIR *dirp);opendir打开目录返回目录流指针失败返回 NULLreaddir读取目录中的下一个条目读到末尾返回 NULL失败也返回 NULL需通过 errno 区分closedir关闭目录流释放资源2. dirent 结构体readdir返回的目录条目结构体核心成员struct dirent { ino_t d_ino; // 文件的inode号 char d_name[256]; // 文件名 };3. 实战遍历目录打印所有文件#include stdio.h #include dirent.h #include sys/stat.h #include string.h int main(int argc, char *argv[]) { if (argc ! 2) { fprintf(stderr, 用法%s 目录路径\n, argv[0]); return 1; } DIR *dir opendir(argv[1]); if (dir NULL) { perror(opendir failed); return 1; } struct dirent *entry; while ((entry readdir(dir)) ! NULL) { // 跳过 . 和 .. 两个特殊目录 if (strcmp(entry-d_name, .) 0 || strcmp(entry-d_name, ..) 0) { continue; } printf(%s\n, entry-d_name); } closedir(dir); return 0; }工程注意readdir 返回的指针指向内部静态缓冲区不保证线程安全多线程场景应使用readdir_r版本。四、文件权限与属性修改1. 修改文件权限chmod/fchmod#include sys/stat.h int chmod(const char *pathname, mode_t mode); int fchmod(int fd, mode_t mode);chmod通过路径修改文件权限fchmod通过已打开的文件描述符修改权限mode参数可以直接写八进制数如0644也可以用权限宏按位或组合2. umask 与默认权限umask是进程的文件权限掩码用于控制新建文件的默认权限。新建文件的默认权限 0666 ~umask新建目录的默认权限 0777 ~umask系统默认 umask 通常是0022因此新建文件默认权限0666 ~0022 0644新建目录默认权限0777 ~0022 0755#include sys/stat.h mode_t umask(mode_t mask);umask 是进程级属性修改只影响当前进程及其子进程不影响系统全局。3. 修改所有者与所属组#include unistd.h int chown(const char *pathname, uid_t owner, gid_t group); int fchown(int fd, uid_t owner, gid_t group); int lchown(const char *pathname, uid_t owner, gid_t group);chown修改文件的所有者和所属组lchown不跟随软链接修改软链接自身的所有者注意只有 root 用户可以修改文件的所有者普通用户只能修改自己拥有的文件的所属组且只能改成自己所在的组五、软硬链接深度对比1. 创建链接的函数#include unistd.h int link(const char *oldpath, const char *newpath); // 创建硬链接 int symlink(const char *target, const char *linkpath); // 创建软链接 int unlink(const char *pathname); // 删除链接/文件unlink删除一个硬链接也就是删除文件名映射。对于普通文件删除最后一个硬链接就等于删除文件对于软链接删除的是链接本身不影响目标文件。2. 软硬链接核心对比对比维度硬链接软链接符号链接本质多个文件名指向同一个 inode独立文件存储目标文件的路径inode 号和源文件相同拥有独立的 inode跨文件系统不可以只能在同一文件系统内可以支持跨分区跨文件系统目录支持不允许给目录创建硬链接支持给目录创建软链接文件大小和源文件完全一致很小只存储目标路径字符串源文件删除不影响文件依然存在软链接失效成为悬空链接相对路径无影响相对路径是相对于链接文件所在位置六、面试高频考点与易错坑点1. 经典面试问答Q1stat 和 lstat 有什么核心区别答 stat 会跟随软链接返回的是软链接指向的目标文件的属性lstat 不会跟随软链接返回的是软链接自身的属性。 因此判断一个文件是不是软链接必须使用 lstat用 stat 永远只能得到目标文件的类型无法判断链接本身。Q2什么是 inode文件名和 inode 是什么关系答 inode 是文件系统中存储文件元数据的结构体每个文件对应唯一的 inode 号inode 里记录了文件的权限、大小、时间、数据块位置等信息。 文件名不是文件的本质只是存放在目录里的别名目录本质上是一张 “文件名→inode 号” 的映射表。系统访问文件时先通过文件名找到 inode 号再通过 inode 找到文件数据。Q3硬链接和软链接有什么本质区别答本质不同硬链接是多个文件名指向同一个 inode共享同一份数据软链接是独立文件存储目标文件的路径有自己的 inode。跨分区硬链接不能跨文件系统软链接可以。目录硬链接不能给目录创建软链接可以。源文件删除删除源文件硬链接不受影响文件依然存在删除源文件后软链接失效成为悬空链接。Q4rm 删除文件后磁盘空间为什么有时候没有立刻释放答 因为文件真正被删除需要满足两个条件一是硬链接计数为 0二是没有进程打开该文件。 如果有进程正在打开并持有文件描述符rm 只是删除了文件名映射硬链接计数减一但进程还在引用文件数据块不会释放。直到进程关闭文件空间才会真正被回收。Q5umask 的作用是什么新建文件的默认权限怎么计算答 umask 是进程的权限掩码用于屏蔽新建文件的部分权限控制默认权限。 新建普通文件基础权限是 0666新建目录是 0777最终默认权限等于基础权限按位取反 umask 后的值。 比如 umask 为 0022 时文件默认权限是 0644目录默认权限是 0755。2. 常见易错坑点用 stat 判断软链接永远得到目标文件类型误以为不是链接必须用 lstat遍历目录时忘记跳过.和..递归遍历会导致无限循环readdir 返回 NULL 就认为遍历结束忽略错误情况需要判断 errno 是否为 0误以为 rm 会立刻释放磁盘空间忽略进程打开文件的引用计数软链接使用相对路径时误以为是相对于当前工作目录实际是相对于链接文件所在目录普通用户调用 chown 修改文件所有者以为会成功实际只有 root 权限才能修改所有者认为硬链接可以跨文件系统实际 inode 号只在单个文件系统内唯一跨分区无法共享 inode以上就是 Linux 目录与文件属性的核心内容。理解 inode 与文件系统底层逻辑才能真正看懂 Linux 文件操作的各种行为排查磁盘空间不释放、权限异常等工程问题。下一篇我们正式进入进程模块讲解进程本质与 fork 创建机制。制作不易如果对你有用希望能点赞收藏支持一下。