插U盘是 /dev/sdb,连串口是 /dev/ttyUSB0,读键盘是 /dev/input/event0。Linux 为什么把所有东西都叫“文件”?因为键盘、网络、定时器、进程信息最终都变成一个 fd,select / poll / epoll 用一个循环就能全部监听。这其实是它最顺手的设计之一。
一、先看现象 /dev 下为什么全是硬件
第一次打开 Linux 的 /dev 目录,很多人会愣住:
$ ls /devsda sdb ttyUSB0 input null zero random
这里没有文档、没有图片,却列着硬盘、串口、键盘、随机数发生器。更奇怪的是,你可以像读文件一样读键盘:
$ sudo cat /dev/input/event0
按下回车,屏幕刷出一堆乱码——那就是按键事件。在 Linux 看来,键盘不过是一个可读的数据流。
本节要点:Linux 把硬件、内核对象、进程信息都放进 /dev、/proc、/sys,打开它们就像打开普通文本。
二、Linux 里的“文件”到底是什么
我们平时说的“文件”指硬盘上的数据,比如 .txt、.mp4。但 Linux 的“文件”是更宽泛的抽象:
文件 = 一段可以通过 open / read / write / close 访问的数据流。
数据存在磁盘、来自键盘缓冲区、还是内核实时生成,都不重要。重要的是接口统一。
| | | |
|---|
| /home/user/note.md | | |
| /dev/sda | | |
| /dev/input/event0 | | |
| /proc/cpuinfo | | |
| socket() | | |
本节要点:Linux 的“文件”是接口抽象,不是磁盘文件。能用四个基本动作访问的数据流,都可以叫文件。
三、键盘、鼠标、网络为什么都是文件
3.1 键盘鼠标
裸机读取键盘要处理中断、扫描码、消抖;Windows 要调专门 API。Linux 只需要:
int fd = open("/dev/input/event0", O_RDONLY);struct input_event ev;read(fd, &ev, sizeof(ev));
一个 read() 拿到按键的时间戳、键码、按下/松开状态。鼠标滚轮、坐标、点击同理。
| |
|---|
| |
| Raw Input / DirectInput API |
| open() + read()/dev/input/eventX |
把输入设备做成文件,应用层就不用再背一套新 API。
3.2 网络
socket 本质上也是文件描述符:
int sock = socket(AF_INET, SOCK_STREAM, 0);write(sock, "hello", 5);read(sock, buf, sizeof(buf));close(sock);
高并发服务器里,每个连接就是一个 fd,全部交给 epoll_wait 统一监听。一个线程管几万个连接,靠的就是这个抽象。
本节要点:键盘鼠标是事件流文件,网络是双向字节流文件。应用层只关心 fd 里读到了什么。
四、/proc 和 /sys 也是文件
/proc 没有真正的磁盘文件,内容都是内核实时生成:
$ cat /proc/cpuinfo # CPU 信息$ cat /proc/meminfo # 内存使用$ cat /proc/1234/status # 进程状态$ ls /proc/1234/fd # 进程打开的文件描述符
/sys 更偏向设备和驱动属性。操作 GPIO 就是写文件:
$ echo 17 > /sys/class/gpio/export$ echo out > /sys/class/gpio/gpio17/direction$ echo 1 > /sys/class/gpio/gpio17/value
| |
|---|
/proc/cpuinfo | |
/proc/PID/fd | |
/sys/class/gpio | |
/sys/class/net/eth0 | |
本节要点:进程、内存、CPU、GPIO 都被抽象成文件,用户空间用最普通的 open/write 就能访问内核数据。
五、这种设计带来什么好处
Unix 哲学里有一条:一切皆文件,所有工具只做一件事,程序之间用文本流协作。 Linux 继承了这个思路。
5.1 统一接口
不管对方是硬盘、键盘、网卡还是内核对象,open / read / write / close / epoll 足够应付大多数场景。学一套接口,管几乎所有资源。
5.2 组合性极强
因为接口统一,任何产生数据的“文件”都能进管道:
$ cat /proc/cpuinfo | grep "model name" | sort | uniq -c
5.3 权限模型复用
文件权限系统直接套在设备文件上:
$ ls -l /dev/ttyUSB0crw-rw---- 1 root dialout 188, 0 Jul 8 10:00 /dev/ttyUSB0
只有 dialout 组能访问串口,不用额外写权限逻辑。
5.4 多路复用简单
select / poll / epoll 监听的是 fd。socket、timerfd、signalfd、eventfd 都是 fd,一个事件循环就能统一管理所有输入来源。
本节要点:一切皆文件带来统一接口、管道组合、权限复用、epoll 统一监听四大好处。
六、注意边界
“一切皆文件”是接口统一,不是语义完全相同:
本节要点:统一的是访问接口,不是语义。读写时仍要尊重每个对象的本性。
七、总结
Linux 的“一切皆文件”,本质是把所有资源都抽象成字节流。不是说所有东西都是磁盘文件,而是说:只要用 open / read / write / close 这套语言描述,键盘、鼠标、网络、进程、GPIO 都能被统一访问。