编程技术分享平台

网站首页 > 技术教程 正文

图解Linux 7种文件类型

xnh888 2025-08-02 22:27:58 技术教程 10 ℃ 0 评论
大家好,这里是物联网心球。
今天,我们来聊聊Linux 7种文件类型。对Linux系统有一定了解的同学一定知道Linux有7种文件类型,分别为:

括号中的字符表示文件类型。在Linux系统中,可通过执行ls -l命令查看文件类型。 ls -l命令可以列出文件的详细信息,包括文件类型,文件类型显示在每行的第一个字符中。

# ls -l
-rw-r--r-- 1 root root 748 Jul 10 09:47 test.c

那么,这7种文件具体都是什么文件,它们有什么作用呢?带着这个问题,我们开始本章内容的学习。

1.普通文件和链接文件
普通文件和链接文件最好放在一起来讲解,通过对比能够深入理解这两种文件类型。
图1 普通文件和链接文件
普通文件和链接文件的实现原理如图1所示。
普通文件通常用于存储: 文本文件、图片、音频、可执行程序等。为了能够永久保存数据, 普通文件通常需要存储在磁盘上。如果只是临时存储数据,普通文件也可以存储在内存中。
以存储在磁盘(文件系统类型为:ext4)为例,磁盘以数据块(4KB)为单位来存储文件。如果文件比较大,则需要多个数据块来存储。Linux内核通过struct inode结构来访问磁盘文件,inode(索引节点)是一个非常重要的数据结构,用于存储文件或目录的元数据。每个文件或目录都对应一个唯一的 inode,它包含了文件的属性和权限等信息,但不存储文件的实际数据内容。
struct inode定义如下(只展示部分关键成员):
structinode
{

umode_t i_mode;//文件类型和权限
loff_t i_size; // 文件大小(字节)
unsignedshort i_bytes; // 文件的字节数
blkcnt_t i_blocks; // 文件占用的块数
structinode_operations *i_op;// inode 操作函数指针
structfile_operations *i_fop;// file 操作函数指针
structaddress_space *i_mapping;// 文件的地址空间对象
};
i_mapping成员指向页缓存, 页缓存是内核用于管理内存中文件数据的缓存机制,通过将文件数据存储在内存页面中,提高文件读写操作的效率,减少对磁盘的直接访问。
i_op 管理 inode元数据操作 (如创建/删除文件),而 i_fop 管理 文件被打开后的操作 (如读写数据),分别对应 struct inode_operations struct file_operations 接口。
文件系统(如ext4)挂载至内核后,文件系统中的目录和文件都会记录在内核文件树。通过文件路径递归查询文件树就能够找到文件(inode结构)。用户程序读写普通文件,其实就是通过inode结构的i_fop成员( 指向file操作函数集 )去读写页缓存。
讲完了普通文件,我们继续来讲解链接文件。 链接文件有两种主要类型: 硬链接 软链接(符号链接) 。虽然二者都是链接文件,但是它们的内核实现原理却不相同。
用户程序不能直接通过硬链接和软链接来读写文件,只能通过源文件(普通文件)来读写文件。硬链接 共享 源文件的inode,用户程序通过硬链接文件路径能够直接找到源文件inode,通过源文件inode就能够读写文件。
软链接不共享源文件的inode,创建软链接时会创建新的inode,软链接有自己的inode,所以软链接通常被认为是独立的文件。软链接inode是一种的特殊的inode,它的作用仅仅是用于查找源文件inode,软链接inode有一个成员(i_data)用于记录源文件路径 。用户程序通过软链接读写文件时,内核会根据软链接文件路径查找到软链接inode,再通过软链接inode记录的源文件路径找到源文件inode,最后通过源文件inode读写文件。
2.目录文件
目录文件是一种特殊的文件,用于存储文件系统中的文件和子目录的元数据信息。它本身并不存储文件内容,而是通过目录项(directory entry)来组织文件和目录的层次结构。
图2 目录文件
如图2所示,每个目录文件都有一个inode,目录文件inode的i_op成员指向inode操作函数集(用于创建、删除文件和子目录等)。Linux系统创建文件时,需要先根据文件路径先查找到父目录,然后通过父目录inode的i_op成员来创建文件。例如:用户程序在home目录下创建一个test.txt文件,用户程序执行创建文件的命令touch /home/test.txt,内核根据/home/test.txt文件路径查找到父目录home,home目录已经存在,所以home目录会有一个inode,通过home目录的inode就能够在home目录下创建test.txt文件了。
3.套接字文件
套接字文件是一种特殊类型的文件,用于实现进程间通信(IPC)。它提供了一个通信端点,允许不同进程之间通过网络协议进行数据交换。套接字文件在文件系统中以文件的形式存在,但其主要功能是实现网络通信,而不是存储数据。
图3 套接字文件
套接字文件是一种用于网络通信的文件,它的种类有很多,例如:IPv4套接字(TCP和UDP套接字)、原始套接字、域套接字等。
以TCP套接字为例,如图3所示。用户程序通过:socket、bind、connect等函数创建并初始化一个套接字文件后,内核会创建一个struct socket结构体对象。socket对象很复杂,它会记录网络通信相关的信息(源IP、目的IP、源端口、目的端口等),同时它也会定义一些函数成员(协议封装、协议解封、发送数据、接收数据等)。用户程序发送数据时,会调用socket对象的函数成员对用户数据进行封装,内核会将封装的网络数据包发送至网卡,由网卡发送至网络。
4.管道文件

管道文件是一种特殊的文件,用于实现本机进程间通信。管道文件(匿名管道和命名管道等)只是内核定义的环形缓冲区。 环形缓冲区是一种固定大小的先进先出(FIFO)数据结构,当缓冲区达到最大容量时,新的数据会覆盖最旧的数据,从而实现数据的循环存储和高效利用。环形缓冲区定义了 写端 读端 ,写端负责将数据写入环形缓冲区,读端负责从环形缓冲区读取数据。

图4 管道文件

以匿名管道为例,如图4所示。用户程序通过pipe函数创建了一个管道文件,内核会定义一个环形缓冲区。pipe函数调用成功后会返回两文件描述符,这个文件描述符分别对应环形缓冲区的读端和写端。用户程序可以通过这两个文件描述符来读写环形缓冲区。由于管道文件对应的环形缓冲区属于内核级别,对于系统中的所有进程都是可见的,所以管道文件通常会用来实现本机进程间通信。

5.字符设备文件

字符设备文件是一种特殊文件,用于访问字符设备。字符设备是以字符流的方式与用户空间程序进行交互的硬件设备,例如串行端口、键盘、鼠标等。字符设备文件提供了一种标准化的接口,使得用户可以通过文件操作(如open、read、write、close)来访问硬件设备。

图5 字符设备文件

字符设备文件实现原理如图5所示。字符设备文件通常位于/dev目录下,dev目录属于devtmpfs文件系统,devtmfps文件系统用来管理字符设备和块设备。字符设备文件通常由内核来创建,创建步骤如下:

dev_t devno;
//方法1:静态分配(需确保设备号未被占用)
register_chrdev_region(devno, count, "mydev");
//方法2:自动分配主设备号
alloc_chrdev_region(&devno, 0, 1, "mydev");

cdev表示一个字符设备。

struct cdev my_cdev;
cdev_init(&my_cdev, &fops); //初始化cdev并关联file_operations

fops为file操作函数集,需由用户自行定义,示例如下:

static struct file_operations fops = {
.open = device_open,
.release = device_release,
.read = device_read,
.write = device_write,
};

static int device_open(struct inode *inode, struct file *file) {
printk(KERN_INFO "Device opened\n");
return0;
}

static int device_release(struct inode *inode, struct file *file) {
printk(KERN_INFO "Device closed\n");
return0;
}

static ssize_t device_read(struct file *file, char __user *buffer, size_t length, loff_t *offset) {
printk(KERN_INFO "Device read\n");
return0;
}

static ssize_t device_write(struct file *file, const char __user *buffer, size_t length, loff_t *offset) {
printk(KERN_INFO "Device write\n");
return length;
}
cdev_add(&my_cdev, devno, 1);  // 注册设备
// 创建设备类 
structclass *cls = class_create(THIS_MODULE, "my_class");
// 生成设备节点
device_create(cls, NULL, devno, NULL, "mydevice");

经过上述步骤就能够在/dev目录下创建一个字符设备文件mydevice,用户程序通过文件路径/dev/ mydevice 就能够读写该字符设备。内核会根据/dev/ mydevice 文件路径查找到字符设备对应的inode,inode结构的i_fop成员指向用户自定义的file操作函数集,用户程序读写字符设备最终执行的是自定义的读写函数。

我们可以换一个角度来理解字符设备文件,用户程序想要在内核执行一段特定代码(由用户自行定义)。用户通过字符设备的file操作函数集来定义这些函数,最后用户程序通过字符设备文件调用这些函数。

6.块设备文件

块设备是以 固定大小的数据块 (通常为512B-4KB)为最小存储单元的硬件设备,支持 随机访问 (如硬盘、SSD、U盘),块设备的核心特点:

图6 块设备文件
块设备文件的实现原理如图6所示。块设备文件同样位于/dev目录下,它的实现过程和字符设备文件类似。与字符设备文件不同的是,块设备通常需要和一个具体的块设备(如磁盘)绑定,块设备定义的file操作函数集用来读写块设备。块设备以数据块为单位进行读写,块设备的读写操作被封装成I/O请求并提交至I/O请求队列,I/O请求将被特定的函数处理。
总结:
Linux 7种文件类型我们已经讲解完毕,我们来做一个简单的总结。7种文件类型的共同点是都是基于VFS(虚拟文件系统)架构设计的,VFS 通过屏蔽底层文件系统的具体实现差异(如Ext4、XFS、NTFS等),为用户态应用程序提供 标准化的文件操作接口 (如 open read write等 )。 由于 7种文件类型属于不同的文件系统(部分文件类型属于相同文件系统),所以7种文件类型实现的功能会存在差异。要想真正理解“ Linux一切皆文件 ”这种设计思想,我们需要多去研究VFS。

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表