linux学习慕课版 第一章 Linux 文件与目录学习笔记
在开篇的第一章里,介绍Linux系统中应用最为广泛的知识:文件的属性特点与文件目录的操作,以及文件系统的概念。对于Linux操作系统而言,一切皆文件,由此可见文件是Linux操作系统的重要组成部分。本章内容有助于读者对后续章节的理解与应用。
一、文件属性
(一)文件类型
Linux 系统中文件类型主要包括以下几种:
1.普通文件(regular file):最常见的文件类型,数据形式可以是文本或二进制数据。
2.目录文件(directory file):这种文件包含其他类型文件的名字以及指向与这些文件有关信息的指针。对一个目录文件有读许可权的任一进程都可以读该目录文件的内容,但只有内核才有写目录文件的权限。
3.字符设备文件(character special file):这种文件类似于字符设备的一种抽象,它代表的是应用程序对硬件设备的访问接口。Linux应用程序通过对该文件进行操作来实现对设备的访问。
4.块设备文件(block special file):用于磁盘设备,与字符设备文件共同抽象 Linux 系统中的所有设备。
5.管道文件(pipe file):用于进程间通信,也称为命名管道。
6.套接字文件(socket file):用于进程间的网络通信或本地通信。
7.符号链接文件(symbolic link file):指向另一个文件,类似于 Windows 系统的快捷方式。
在 Linux 系统终端输入 “ls –l 目录名”,可查看到目录下的所有文件及类型。文件类型通常用一个字符表示,具体如下表所示:
文件类型
字符表示
普通文件
-
目录文件
d
字符设备文件
c
块设备文件
b
管道文件
p
套接字文件
s
符号链接文件
l
(二)符号链接文件
Linux 中有硬链接和软链接两种类型的链接:
硬链接:利用 Linux 系统为每个文件分配的物理编号 i 节点建立链接,不能跨越文件系统,文件属性与源文件基本一致,二者可同步更新,类似于 Windows 系统中将文件复制一份。
软链接:利用文件的路径名建立链接,通常使用绝对路径以保证可移植性,类似于 Windows 中创建快捷方式,其权限不会改变源文件的权限。
二者的不同之处在于,源文件删除后,软链接无法定位到源文件,会显示没有文件;硬链接类似于复制,删除源文件后,硬链接依然可以访问。但如果删除源文件后重新创建一个同名文件,软链接将恢复,硬链接则不再有效,因为文件的 i 节点已经改变。
此外,修改链接的目标文件名,硬链接依然有效,软链接将断开;对一个已存在的符号链接文件执行移动或删除操作,有可能导致链接的断开。
(三)stat () 函数、fstat () 函数和 lstat () 函数
这三个函数用于获取文件属性,其函数原型如下:
c
运行
#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>int stat(const char *path, struct stat *buf);int fstat(int fd, struct stat *buf);int lstat(const char *path, struct stat *buf);
stat () 函数:得到与 path 所指定文件有关的信息结构,并保存在 buf 中。
fstat () 函数:需要将文件打开之后的文件描述符作为参数,功能与 stat () 函数一致。
lstat () 函数:类似于 stat () 函数,只不过其参数 path 指向的文件是一个符号链接时,返回符号链接的有关信息,而不是由该符号链接引用的文件的信息。
buf 指向的结构体 stat 的基本形式如下:
c
运行
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* inode number */
mode_t st_mode; /* protection */
nlink_t st_nlink; /* number of hard links */
uid_t st_uid; /* user ID of owner */
gid_t st_gid; /* group ID of owner */
dev_t st_rdev; /* device ID (if special file) */
off_t st_size; /* total size, in bytes */
blksize_t st_blksize; /* blocksize for file system I/O */
blkcnt_t st_blocks; /* number of 512B blocks allocated */
time_t st_atime; /* time of last access */
time_t st_mtime; /* time of last modification */
time_t st_ctime; /* time of last status change */};
通过读取该结构体成员,可获取文件的各种属性。
(四)文件属主
文件都有特定的所有者(属主)和所属组(属组),每个文件关联用户 ID (UID) 和组 ID (GID)。可通过 chown ()、lchown () 和 fchown () 函数改变用户 ID 和组 ID,函数原型如下:
c
运行
#include <unistd.h>int chown(const char *path, uid_t owner, gid_t group);int fchown(int fd, uid_t owner, gid_t group);int lchown(const char *path, uid_t owner, gid_t group);
chown () 函数:改变 path 指定文件的属主。
lchown () 函数:若 path 为符号链接,改变的是符号链接文件本身的所有权。
fchown () 函数:通过打开文件描述符 fd 改变文件所有权。
(五)文件的存取许可权
每个文件对应 9 种存取许可权,分为属主、同组用户和其他用户三类,如下表所示:
类别
读
写
执行
属主
S_IRUSR
S_IWUSR
S_IXUSR
同组用户
S_IRGRP
S_IWGRP
S_IXGRP
其他用户
S_IROTH
S_IWOTH
S_IXOTH
这些宏在 <sys/stat.h> 中定义,本质是八进制数,可通过位运算转换。例如,宏 I_SRWXU 表示用户对文件拥有可读、可写、可执行的权限,即 I_SRUSR|I_SWUSR|I_SXUSR。
对于目录,读许可权允许读目录获得所有文件名列表,写许可权和执行许可权决定能否在该目录中创建或删除文件。
(六)chmod () 函数和 fchmod () 函数
这两个函数用于更改文件的存取许可权,原型如下:
c
运行
#include <sys/stat.h>int chmod(const char *path, mode_t mode);int fchmod(int fd, mode_t mode);
chmod () 函数:对指定文件进行权限修改。
fchmod () 函数:对已打开的文件进行权限修改。
要改变文件许可权限,进程的有效用户需是文件所有者或具有超级用户许可权,可通过终端输入 “sudo chmod 权限 文件” 修改文件权限。
(七)文件的长度
stat 结构体中的成员 st_size 指定了文件以字节为单位的长度,对普通文件、目录文件和符号连接有意义:
普通文件:长度可以是 0,读时得到文件结束指示。
目录:长度通常是 16 或 512 的整倍数。
符号连接:长度是文件名中的实际字节数,不包含 null 字符。
普通文件可能出现空洞,即位移超过文件结尾端并写入数据,空洞不占用磁盘空间,直到写入数据时才分配磁盘块,这会导致文件名义大小可能大于占用的磁盘存储总量。可通过 “ls -l” 和 “du -sh” 命令查询空洞文件。
(八)文件的截取
可通过 truncate () 和 ftruncate () 函数截短文件,原型如下:
c
运行
#include <unistd.h>#include <sys/types.h>int truncate(const char *path, off_t length);int ftruncate(int fd, off_t length);
这两个函数将路径名 path 或打开的文件描述符 fd 所指定的文件截短为 length 长度,若原长度大于 length,超出部分无法存取;若原长度小于 length,文件将被扩充,扩充部分填充实空字符。
(九)更改文件名
通过 rename () 函数重命名文件或移至同一文件系统中的另一目录,原型如下:
c
运行
#include <stdio.h>int rename(const char *oldpath, const char *newpath);
该函数仅操作目录条目,不移动文件数据,若 newpath 已存在则覆盖,若指向同一文件则不变化。若 oldpath 为文件,newpath 不能为目录路径名;若 oldpath 为目录,newpath 必须不存在或为空目录,且不能包含 oldpath 作为目录前缀。
(十)文件的时间戳
stat 结构体中的 st_atime、st_mtime、st_ctime 字段表示文件时间戳,分别记录上次访问时间、上次修改时间和文件状态上次变更时间,类型为 time_t,记录形式为自 1970 年 1 月 1 日到当前系统时间的秒数。
可通过 utime、utimes、futimes、lutimes 等函数改变文件时间戳,其中 utimes () 函数可精确到微秒级。
二、目录操作
(一)mkdir () 函数和 rmdir () 函数
mkdir () 函数:创建目录,原型为int mkdir(const char *pathname, mode_t mode);,pathname 为目录名,mode 是文件存取许可权,可被进程文件权限掩码修改。
rmdir () 函数:删除空目录,原型为int rmdir(const char *pathname);。
(二)读目录
通过 opendir () 和 readdir () 函数读取目录:
opendir () 函数:打开目录,返回指向 DIR 结构的指针,原型为DIR *opendir(const char *name);。
readdir () 函数:读取目录,返回 dirent 结构体指针,原型为struct dirent *readdir(DIR *dirp);。
dirent 结构体定义如下:
c
运行
struct dirent {
ino_t d_ino; /* inode number */
off_t d_off; /* offset to the next dirent */
unsigned short d_reclen; /* length of this record */
unsigned char d_type; /* type of file */
char d_name[256]; /* filename */};
(三)解析路径名字符串
dirname () 和 basename () 函数将路径名字符串分解成目录和文件名两部分,原型如下:
c
运行
#include <libgen.h>char *dirname(char *path);char *basename(char *path);
使用时需注意忽略 path 尾部斜线字符,以及不同 path 情况的处理。
三、文件系统
(一)文件系统的概念
文件系统是用于组织和管理计算机存储设备上大量文件的机制,功能包括管理存储空间、提供文件逻辑和物理结构、实现文件映射、控制和存取操作以及实现文件共享与保护。
(二)文件系统的类型
磁盘文件系统:本地可访问,驻留在磁盘上,常见格式有 EXT3、EXT4、VFAT、FAT、FAT16、FAT32、NTFS 等。
网络文件系统:可远程访问,常见格式有 NFS、Samba 等。
虚拟文件系统(VFS):不驻留在磁盘上,是物理文件系统与服务应用之间的接口层,对文件系统细节抽象,使不同文件系统在 Linux 核心及进程看来相同。
(三)文件系统的结构
Linux 文件系统组织成倒置树状结构,所有存储设备作为子目录,与 Windows 系统将目录属于分区不同,Linux 中分区属于目录结构。Linux 将硬件视为文件处理,通过挂载将硬件文件系统挂载到目录树子目录,如 U 盘挂载到 /media/DISK_IMG 目录,而 Windows 将 USB 存储器作为新驱动器。
四、本章小结
本章介绍了 Linux 系统中文件与目录的基本概念,包括文件属性、目录操作和文件系统的概念,重点掌握了文件目录的属性及相关函数接口的使用,为后续学习 Linux 操作系统打下基础。