
🎬 个人主页 :艾莉丝努力练剑
❄专栏传送门 :《C语言》《数据结构与算法》《C/C++干货分享&学习过程记录》
《Linux操作系统编程详解》《笔试/面试常见算法:从基础到进阶》《Python干货分享》
⭐️为天地立心,为生民立命,为往圣继绝学,为万世开太平
🎬 艾莉丝的简介:

文章目录
- [1 ~> 文件操作:C语言文件操作 + 系统级别文件操作](#1 ~> 文件操作:C语言文件操作 + 系统级别文件操作)
-
- [1.1 基础认知](#1.1 基础认知)
- [1.2 C语言文件操作(库函数层面)](#1.2 C语言文件操作(库函数层面))
-
- [1.2.1 关键细节与示例](#1.2.1 关键细节与示例)
- [1.2.2 要点补充](#1.2.2 要点补充)
- [1.3 系统级别文件操作(系统调用层面)](#1.3 系统级别文件操作(系统调用层面))
-
- [1.3.1 关键细节与示例](#1.3.1 关键细节与示例)
- [1.3.2 要点补充(含open函数)](#1.3.2 要点补充(含open函数))
- [2 ~> 文件描述符fd](#2 ~> 文件描述符fd)
-
- [2.1 文件描述符的核心定义](#2.1 文件描述符的核心定义)
- [2.2 默认fd与对应设备文件](#2.2 默认fd与对应设备文件)
- [2.3 分配规则](#2.3 分配规则)
- [2.4 内核底层结构:核心](#2.4 内核底层结构:核心)
- [3 ~> 重定向](#3 ~> 重定向)
-
- [3.1 核心定义](#3.1 核心定义)
- [3.2 基础重定向示例(基于fd分配规则)](#3.2 基础重定向示例(基于fd分配规则))
- [3.3 dup2系统调用(重定向专用的接口)](#3.3 dup2系统调用(重定向专用的接口))
- [3.4 minishell中添加重定向功能(核心逻辑)](#3.4 minishell中添加重定向功能(核心逻辑))
- [4 ~> 如何理解"一切皆文件"](#4 ~> 如何理解“一切皆文件”)
-
- [4.1 多态调用和"一切皆文件"的关系](#4.1 多态调用和“一切皆文件”的关系)
- [4.2 "一切皆文件"的核心本质](#4.2 “一切皆文件”的核心本质)
- [4.3 底层实现(FILE与file_operations结构体)](#4.3 底层实现(FILE与file_operations结构体))
- [4.4 总结"一切皆文件"](#4.4 总结“一切皆文件”)
- [5 ~> 缓冲区](#5 ~> 缓冲区)
-
- [5.1 缓冲区的定义、作用、引入原因](#5.1 缓冲区的定义、作用、引入原因)
-
- [5.1.1 缓冲区的定义](#5.1.1 缓冲区的定义)
- [5.1.2 缓冲区的核心作用](#5.1.2 缓冲区的核心作用)
- [5.1.3 一句话说明为什么要引入缓冲区机制](#5.1.3 一句话说明为什么要引入缓冲区机制)
- [5.2 缓冲类型(标准IO库,C库提供)](#5.2 缓冲类型(标准IO库,C库提供))
- [5.3 缓冲区刷新条件](#5.3 缓冲区刷新条件)
- [5.4 关键示例:缓冲区的坑以及验证](#5.4 关键示例:缓冲区的坑以及验证)
- [5.5 库函数与系统调用的缓冲区差异](#5.5 库函数与系统调用的缓冲区差异)
- [5.6 FILE结构体与缓冲区:关联底层](#5.6 FILE结构体与缓冲区:关联底层)
- [5.7 自定义简易libc IO库(理解缓冲区实现)](#5.7 自定义简易libc IO库(理解缓冲区实现))
- [6 ~> 打通C语言与系统IO的关联(核心总结)](#6 ~> 打通C语言与系统IO的关联(核心总结))
-
- [6.1 库函数与系统调用的关系](#6.1 库函数与系统调用的关系)
- [6.2 关键关联点](#6.2 关键关联点)
- [6.3 核心总结](#6.3 核心总结)
- 结尾

1 ~> 文件操作:C语言文件操作 + 系统级别文件操作
1.1 基础认知
文件 = 属性(元数据)+ 内容,所有文件操作本质是「内容操作」和「属性操作」;Linux下一切皆文件(磁盘、键盘、显示器、网卡等均被抽象为文件),文件操作本质是进程对文件的操作,底层依赖操作系统的系统调用,而非直接通过语言库函数。
注:0KB空文件占用磁盘空间(仅存储属性);磁盘是永久性外设,文件存储具有持久性,文件操作本质是对外设的IO操作。
1.2 C语言文件操作(库函数层面)
核心函数:fopen、fread、fwrite、fclose,依赖stdio.h头文件,返回值为FILE*(文件指针),底层封装系统调用,提供用户级缓冲区。
1.2.1 关键细节与示例
c
#include <stdio.h>
#include <string.h>
// 1. 打开文件(w模式:不存在则创建,存在则清空)
FILE *fp = fopen("myfile", "w");
if(!fp){ printf("fopen error!\n"); return 1; }
// 2. 写文件(往myfile写入5次hello bit!)
const char *msg = "hello bit!\n";
int count = 5;
while(count--){
fwrite(msg, strlen(msg), 1, fp); // 参数:内容、单个元素长度、元素个数、文件指针
}
// 3. 读文件(读取myfile内容,类比fwrite)
FILE *fp = fopen("myfile", "r");
char buf[1024];
while(1){
ssize_t s = fread(buf, 1, strlen(msg), fp);
if(s > 0){ buf[s] = 0; printf("%s", buf); }
if(feof(fp)){ break; } // 检测文件结束
}
// 4. 关闭文件(必须执行,刷新缓冲区+释放资源)
fclose(fp);
1.2.2 要点补充
-
1、C默认打开3个流:stdin(标准输入,对应键盘,fd=0)、stdout(标准输出,对应显示器,fd=1)、stderr(标准错误,对应显示器,fd=2),类型均为FILE*;
-
2、打开方式核心区别:r(只读,文件不存在报错)、w(只写,创建/清空)、a(追加,创建/写末尾)、r+/w+/a+(读写,区别在于是否创建、是否清空);

- 3、简单实现
cat命令:通过命令行参数argv[1]获取文件名,循环fread读取内容并printf输出。
1.3 系统级别文件操作(系统调用层面)
核心函数: open、read、write、close,依赖fcntl.h、unistd.h等头文件,是文件操作的底层接口,无用户级缓冲区,直接与内核交互。
1.3.1 关键细节与示例
c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
// 1. 打开/创建文件(核心参数:路径、标志位、权限)
umask(0); // 清除权限掩码,确保创建文件权限为0644
int fd = open("myfile", O_WRONLY|O_CREAT, 0644);
if(fd < 0){ perror("open"); return 1; } // 失败返回-1,perror打印错误信息
// 2. 写文件(类比fwrite,无缓冲区)
const char *msg = "hello bit!\n";
int len = strlen(msg);
int count = 5;
while(count--){
write(fd, msg, len); // 参数:文件描述符、内容、长度,返回实际写入字节数
}
// 3. 读文件(类比fread)
int fd = open("myfile", O_RDONLY);
char buf[1024];
while(1){
ssize_t s = read(fd, buf, strlen(msg));
if(s > 0){ printf("%s", buf); }
else{ break; } // s=0(文件结束)或-1(错误),退出循环
}
// 4. 关闭文件
close(fd);
1.3.2 要点补充(含open函数)
1、open 函数核心参数:
-
flags(必选1个,可选多个用|连接):O_RDONLY(只读)、O_WRONLY(只写)、O_RDWR(读写)、O_CREAT(创建)、O_APPEND(追加)、O_TRUNC(清空);
-
mode:仅O_CREAT存在时有效,指定文件权限(如0644:所有者读写、组只读、其他只读),受umask掩码影响(需提前
umask(0)清除------就近原则);

2、返回值: 成功返回文件描述符(非负整数),失败返回-1;
3、标志位传递逻辑: 通过位或(|)组合,如O_WRONLY|O_CREAT,表示"只写打开,文件不存在则创建",底层通过位与(&)判断标志位是否生效。
2 ~> 文件描述符fd

2.1 文件描述符的核心定义
文件描述符(fd)是Linux中用于标识 "已打开文件"的非负小整数 ,本质:fd是进程中files_struct结构体中fd_array数组的下标,通过fd可找到对应的file结构体(内核中描述已打开文件的对象)。
2.2 默认fd与对应设备文件
Linux进程默认打开3个文件描述符,固定对应如下设备,无需手动open:
-
fd = 0:标准输入(
stdin),对应键盘; -
fd = 1:标准输出(
stdout),对应显示器; -
fd = 2:标准错误(
stderr),对应显示器。
c
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main(){
char buf[1024];
ssize_t s = read(0, buf, sizeof(buf)); // 从fd=0(键盘)读取
if(s > 0){
buf[s] = 0;
write(1, buf, strlen(buf)); // 写入fd=1(显示器)
write(2, buf, strlen(buf)); // 写入fd=2(显示器)
}
return 0;
}
2.3 分配规则
核心规则: 在
fd_array数组中,分配「当前未被使用的最小下标」作为新的文件描述符。

c
#include <stdio.h>
#include <fcntl.h>
int main(){
close(0); // 关闭fd=0(释放该下标)
int fd = open("myfile", O_RDONLY); // 分配最小未使用下标0
printf("fd: %d\n", fd); // 输出fd: 0
close(fd);
return 0;
}
注: 关闭fd = 1或fd = 2后,新open的文件fd会分别变为1或2,这是重定向的底层原理。

2.4 内核底层结构:核心
-
1、进程结构体
task_struct(/usr/src/kernels/.../include/linux/sched.h):包含指针*files,指向files_struct结构体; -
2、
files_struct结构体 (/usr/src/kernels/.../include/linux/fdtable.h):核心是fd_array指针数组,每个元素指向file结构体; -
3、
file结构体 (/usr/src/kernels/.../include/linux/fs.h):描述已打开文件的元信息(inode、权限、读写位置等),包含f_op指针(指向file_operations结构体)。
3 ~> 重定向
3.1 核心定义
重定向:改变文件描述符对应的"实际文件/设备",使原本输出到A设备的内容,输出到B文件/设备(常见:> 输出重定向、>> 追加重定向、< 输入重定向)。
本质:修改进程fd_array数组中,对应fd下标指向的file指针,使其指向目标文件(而非默认设备)。
3.2 基础重定向示例(基于fd分配规则)
c
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
int main(){
close(1); // 关闭fd=1(原本指向显示器)
// 新打开文件,分配最小未使用下标1,此时fd=1指向myfile
int fd = open("myfile", O_WRONLY|O_CREAT, 0644);
if(fd < 0){ perror("open"); return 1; }
printf("fd: %d\n", fd); // 原本输出到显示器,现在输出到myfile(fd=1)
fflush(stdout); // 强制刷新缓冲区(否则可能不写入)
close(fd);
exit(0);
}
现象: printf输出的内容不会显示在显示器,而是写入myfile文件中。
3.3 dup2系统调用(重定向专用的接口)
- 函数原型:
int dup2(int oldfd, int newfd);(将newfd重定向到oldfd,使newfd指向oldfd对应的文件)
不过这个newfd和oldfd的名字取得不好,如果掉个个儿会好理解不少。
- dup2系统调用核心作用: 简化重定向代码,无需手动
close(fd),直接关联两个fd。
c
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main() {
// 打开log文件,获取oldfd
int oldfd = open("./log", O_CREAT | O_RDWR, 0644);
if (oldfd < 0) { perror("open"); return 1; }
// 将fd=1(stdout)重定向到oldfd(log文件)
dup2(oldfd, 1);
// 后续printf都会写入log文件,而非显示器
char buf[1024] = {0};
while(1){
read(0, buf, sizeof(buf)-1);
printf("%s", buf);
fflush(stdout);
}
return 0;
}
3.4 minishell中添加重定向功能(核心逻辑)
-
1、解析命令行:识别重定向符号(<、>、>>),分离命令与目标文件名;
-
2、重定向实现(子进程中执行):根据重定向类型,open目标文件,用dup2关联对应fd(输入重定向关联fd=0,输出/追加关联fd=1);
-
3、核心代码片段(关键逻辑):
c
#define InputRedir 1 // < 输入重定向
#define OutputRedir 2 // > 输出重定向
#define AppRedir 3 // >> 追加重定向
int redir = NoneRedir; // 重定向类型
char *filename = nullptr; // 目标文件名
// 解析重定向符号(从命令行末尾反向查找)
void ParseRedir(char command_buffer[], int len){
int end = len - 1;
while(end >= 0){
if(command_buffer[end] == '<'){
redir = InputRedir;
command_buffer[end] = 0;
filename = &command_buffer[end]+1;
break;
}else if(command_buffer[end] == '>'){
if(command_buffer[end-1] == '>'){
redir = AppRedir;
command_buffer[end-1] = 0;
}else{
redir = OutputRedir;
}
command_buffer[end] = 0;
filename = &command_buffer[end]+1;
break;
}
end--;
}
}
// 执行重定向(子进程中调用)
void DoRedir(){
if(redir == InputRedir){ // 输入重定向:fd=0关联文件
int fd = open(filename, O_RDONLY);
dup2(fd, 0);
}else if(redir == OutputRedir){ // 输出重定向:fd=1关联文件(清空)
int fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
dup2(fd, 1);
}else if(redir == AppRedir){ // 追加重定向:fd=1关联文件(追加)
int fd = open(filename, O_CREAT | O_WRONLY | O_APPEND, 0666);
dup2(fd, 1);
}
}
4 ~> 如何理解"一切皆文件"
4.1 多态调用和"一切皆文件"的关系
Linux "一切皆文件" 和多态(尤其是 C 语言中通过函数指针实现的多态思想)有极强的关联,而且多态是 "一切皆文件" 能够落地的核心底层支撑。
-
1、一切皆文件: 统一对外提供
open/read/write/close接口,屏蔽设备差异; -
2、多态体现(贴合课件结构体):
file_operations结构体中的 read/write 等是函数指针(统一接口),不同设备(键盘 / 磁盘)给这些指针赋不同实现; -
3、落地:调用
read (fd,...)时,内核通过fd找到file->f_op,执行对应设备的read逻辑,即 "同一接口,不同实现"。
注:非 OOP 类多态,是 C 语言函数指针多态,课件第四章 file_operations 结构体就是直接体现。
4.2 "一切皆文件"的核心本质
Linux将所有设备(键盘、显示器、磁盘、网卡)、管道、socket等,均抽象为 "文件" ,统一用一套文件操作接口(open、read、write、close)访问,简化开发。
核心好处: 开发者无需区分设备类型,只需调用相同的IO接口,即可操作所有系统资源(读文件、读键盘、写显示器、网络通信均可用read/write)。
4.3 底层实现(FILE与file_operations结构体)

- 1、FILE结构体:每个已打开的"文件 / 设备",内核都会创建一个FILE结构体,存储其元信息(inode、权限、读写位置、f_op指针等);
-
file_operations结构体:核心是"函数指针数组",每个函数指针对应一个文件操作(
read、write、open、close等),不同设备对应不同的函数实现; -
关联逻辑:file结构体的f_op指针,指向该设备对应的file_operations结构体,当调用read/write时,内核通过f_op找到对应设备的
read / write实现,完成具体操作。
关键结构体片段
c
// FILE结构体(核心成员)
struct file {
struct inode *f_inode; // 文件inode(元数据)
const struct file_operations *f_op; // 指向操作函数集
loff_t f_pos; // 当前读写位置
unsigned int f_flags; // 打开权限
fmode_t f_mode; // 访问模式(只读/只写等)
};
// file_operations结构体(核心成员,函数指针)
struct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int); // 移动读写位置
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); // 读操作
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); // 写操作
int (*open) (struct inode *, struct file *); // 打开操作
int (*release) (struct inode *, struct file *); // 关闭操作
// 其他操作(ioctl、mmap等)
};
4.4 总结"一切皆文件"
"一切皆文件" 的核心是"抽象与统一":操作系统(OS)通过
FILE结构体抽象所有资源,通过file_operations结构体统一操作接口,不同设备只需实现自身的read / write等函数,即可被系统识别和访问,无需修改上层IO逻辑。
5 ~> 缓冲区
5.1 缓冲区的定义、作用、引入原因
5.1.1 缓冲区的定义
缓冲区是内存空间的一部分。也就是说,在内存空间中预留了一定的存储空间,这些存储空间用来缓冲输入或输出的数据,这部分预留的空间就叫做缓冲区。缓冲区根据其对应的是输入设备还是输出设备,分为输入缓冲区和输出缓冲区。
缓冲区:内存中预留的一块存储空间,用于缓存输入 / 输出数据(IO),减少系统调用次数,协调CPU(高速)与外设(低速,磁盘、显示器等)的速度差异,提升程序执行效率。
5.1.2 缓冲区的核心作用
缓冲区的核心作用: 减少CPU状态切换(用户态→内核态)的损耗(系统调用需切换状态,频繁调用损耗大),例如:一次读取大量数据到缓冲区,后续访问直接操作内存,无需再次调用read。
5.1.3 一句话说明为什么要引入缓冲区机制
为了减少使用系统调用的次数,提高效率 ,我们就可以采用缓冲机制 。比如我们从磁盘里取信息,可以在磁盘文件进行操作时,可以一次从文件中读出大量的数据到缓冲区中,以后对这部分的访问就不需要再使用系统调用了,等缓冲区的数据取完后再去磁盘中读取,这样就可以减少磁盘的读写次数,再加上计算机对缓冲区的操作大大快于对磁盘的操作,故应用缓冲区可大大提高计算机的运行速度。
5.2 缓冲类型(标准IO库,C库提供)
标准IO库(
printf、fwrite等)提供3种缓冲类型(全缓冲、行缓冲、无缓冲 ),系统调用(read、write)无缓冲区:
-
1、全缓冲区:填满缓冲区后,才执行系统调用(默认用于磁盘文件),一般普通文件就是全缓存;
-
2、行缓冲区:遇到换行符(\n)或缓冲区填满,执行系统调用(默认用于终端,如stdin、stdout),显示器就是行缓冲;
-
3、无缓冲区:不缓存数据,直接执行系统调用(默认用于stderr,确保错误信息及时显示)。
5.3 缓冲区刷新条件
缓冲区刷新条件重点结论:
-
1、缓冲区填满;
-
2、调用
fflush函数(强制刷新,如fflush(stdout)); -
3、进程正常结束(自动刷新缓冲区);
-
4、关闭文件(fclose会自动刷新缓冲区)。
5.4 关键示例:缓冲区的坑以及验证
c
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
close(1); // 关闭stdout(fd=1)
// 重定向fd=1到log.txt(磁盘文件,全缓冲)
int fd = open("log.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);
printf("hello world: %d\n", fd); // 写入缓冲区,未填满,不刷新
close(fd); // 未刷新缓冲区,log.txt为空
return 0;
}
解决方法: 在close(fd)前添加fflush(stdout),强制刷新缓冲区,内容才会写入文件。
易错点:将fd = 2(stderr,标准错误流)重定向到文件,用perror输出,无需fflush,内容直接写入(因为stderr无缓冲)。
5.5 库函数与系统调用的缓冲区差异
c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int main() {
const char *msg0="hello printf\n";
const char *msg1="hello fwrite\n";
const char *msg2="hello write\n";
printf("%s", msg0); // 库函数,有缓冲区
fwrite(msg1, strlen(msg1), 1, stdout); // 库函数,有缓冲区
write(1, msg2, strlen(msg2)); // 系统调用,无缓冲区
fork(); // 父子进程写时拷贝,缓冲区数据被复制
return 0;
}
观察到的现象:重定向到文件(全缓冲)后,printf和fwrite输出2次(父子各1次),write输出1次(无缓冲,已提前写入)。
结论:
printf、fwrite(C库函数,被C语言封装的系统调用)有用户级缓冲区(C标准库提供),write(系统调用)无缓冲区;缓冲方式会随输出目标变化(终端→行缓冲,文件→全缓冲)。
5.6 FILE结构体与缓冲区:关联底层
C语言标准库中的**FILE结构体**,其本质是:"封装了fd + 用户级缓冲区",核心成员如下:
c
typedef struct _IO_FILE FILE;
struct _IO_FILE {
int _flags; // 缓冲类型(全缓冲/行缓冲/无缓冲)
int _fileno; // 封装的文件描述符(fd)
char* _IO_write_base; // 缓冲区起始地址
char* _IO_write_ptr; // 缓冲区当前写入位置
char* _IO_write_end; // 缓冲区结束地址
// 其他缓冲区相关成员
};
核心逻辑: FILE* fp = fopen(...) ,本质是创建FILE结构体,打开文件获取fd,初始化缓冲区,后续fread / fwrite均操作缓冲区,满足条件后调用系统调用刷新到内核。
5.7 自定义简易libc IO库(理解缓冲区实现)
核心思路: 我们模拟FILE结构体,实现myfopen、myfwrite、myfflush、myfclose,封装fd和缓冲区,手动控制刷新逻辑------艾莉丝这里简单写一段demo,帮助我们理解缓冲区。
c
// my_stdio.h
#pragma once
#define SIZE 1024
#define FLUSH_LINE 1 // 行缓冲
#define FLUSH_FULL 2 // 全缓冲
struct IO_FILE {
int flag; // 缓冲类型
int fileno; // 文件描述符
char outbuffer[SIZE]; // 用户级缓冲区
int size; // 缓冲区当前数据长度
int cap; // 缓冲区容量(SIZE)
};
typedef struct IO_FILE mFILE;
mFILE *myfopen(const char *filename, const char *mode);
int myfwrite(const void *ptr, int num, mFILE *stream);
void myfflush(mFILE *stream);
void myfclose(mFILE *stream);
核心实现:mfopen打开文件获取fd,初始化缓冲区;mfwrite将数据写入缓冲区,满足条件(行缓冲遇\n、全缓冲填满)调用mfflush;mfflush调用write将缓冲区数据写入内核,清空缓冲区;mfclose关闭文件前刷新缓冲区。
6 ~> 打通C语言与系统IO的关联(核心总结)
6.1 库函数与系统调用的关系
核心关系:C语言文件操作库函数(fopen、fread等),是对系统调用接口(open、read等)的封装,目的是提供用户级缓冲区,简化开发、提升效率。
层级关系(从上到下):用户程序 → C标准库(库函数,带缓冲区) → 系统调用接口(无缓冲区) → 内核 → 硬件设备。
6.2 关键关联点
-
1、FILE* 与 fd:FILE结构体封装了fd,fopen本质是调用open获取fd,再初始化缓冲区,后续所有库函数操作,最终都会通过fd调用系统调用;
-
2、缓冲区关联:C库提供用户级缓冲区,内核也有内核级缓冲区(提升整机性能),库函数刷新缓冲区后,数据进入内核缓冲区,内核再按需写入硬件;
-
3、操作逻辑关联:无论是fwrite还是write,最终都是通过内核的file_operations结构体,调用对应设备的写函数,完成数据写入;
-
4、重定向关联:重定向修改的是fd对应的file指针,库函数(printf)操作stdout(fd=1),底层还是通过fd访问文件,因此重定向对库函数和系统调用均生效。
6.3 核心总结
-
1、所有文件操作的底层,都是系统调用,库函数只是"中间层",核心作用是提供缓冲区;
-
2、fd是内核识别文件的标识,FILE*是C库封装后的标识,二者一一对应;
-
3、缓冲区分为"用户级(C库提供)"和"内核级(OS提供)",用户程序的数据,需经过两次刷新(用户→内核→硬件),才能最终写入设备;
-
4、Linux"一切皆文件",统一了IO接口,使得库函数与系统调用的封装更加合理,开发者无需关注底层设备差异。
结尾
uu们,本文的内容到这里就全部结束了,艾莉丝在这里再次感谢您的阅读!
结语:希望对学习Linux相关内容的uu有所帮助,不要忘记给博主"一键四连"哦!
往期回顾:
【Linux:文件】基础IO:文件操作的系统调用和库函数各个接口汇总及代码演示
🗡博主在这里放了一只小狗,大家看完了摸摸小狗放松一下吧!🗡 ૮₍ ˶ ˊ ᴥ ˋ˶₎ა
