Linux入门DAY27(文件IO(系统调用)详解|open/read/write/lseek)

#Linux #嵌入式 #文件IO #系统调用 #C语言

📖前言

在Linux嵌入式开发中,文件IO是非常核心的基础知识点。Linux秉承一切皆文件的设计思想,普通文件、终端、设备、管道、套接字都可以通过文件接口操作 。

文件IO属于系统调用,由内核直接提供接口;而我们平时用的 fopen、fread 属于标准IO库函数,标准IO底层本质还是封装文件IO系统调用,并且增加用户态缓冲区提升效率 。

面试高频考点:文件描述符、open标志位、缓冲区机制、文件IO与标准IO区别、常见坑点(文件描述符泄漏、读写返回值处理)。本文结合手写笔记,梳理全套接口与易错点。

一、文件IO基本概念

文件IO是Linux内核为用户空间提供的文件操作接口,属于系统调用。

四大核心系统调用: open() 、 read() 、 write() 、 close() ,辅助接口: lseek() 。

文件描述符 fd

  1. 进程打开一个文件,内核分配一个非负小整数作为标识,就是文件描述符fd。

  2. 进程默认占用3个文件描述符:

  • 0 :标准输入 stdin

  • 1 :标准输出 stdout

  • 2 :标准错误 stderr

  1. 分配规则:最小未被使用的文件描述符。

  2. 每个进程有最大可打开文件数,打开不关闭会造成文件描述符泄漏。

二、系统调用API详解

1.open 打开/创建文件

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

int open(const char *pathname, int flags);

int open(const char *pathname, int flags, mode_t mode);

功能:打开文件;文件不存在可创建文件,返回文件描述符。

  • pathname :文件路径

  • flags :打开方式标志位,多个标志位用 | 或运算拼接

  • mode :创建文件时才生效,设置文件权限;实际权限 = mode & ~umask

flags常用标志

标志 含义 等价fopen模式

O_RDONLY 只读 "r"

O_WRONLY 只写

O_RDWR 读写 "r+"

O_CREAT 文件不存在则创建

O_TRUNC 打开清空文件原有内容 "w"

O_APPEND 追加写,光标指向文件末尾 "a"

模式等价关系

  • "w" : O_WRONLY | O_CREAT | O_TRUNC

  • "w+" : O_RDWR | O_CREAT | O_TRUNC

  • "a" : O_WRONLY | O_CREAT | O_APPEND

  • "a+" : O_RDWR | O_CREAT | O_APPEND

返回值:成功返回fd;失败返回 ‑1 。

2.close 关闭文件

#include <unistd.h>

int close(int fd);

  • 功能:关闭文件,释放文件描述符资源

  • 参数:open返回的文件描述符fd

  • 返回:成功返回0;失败返回‑1

⚠面试坑:文件打开完成必须close;不关闭会发生文件描述符泄漏,耗尽进程可用fd资源。

3.write 向文件写入数据

#include <unistd.h>

ssize_t write(int fd, const void *buf, size_t count);

  • fd:目标文件描述符

  • buf:要写入数据的首地址

  • count:希望写入的字节数

  • 返回:成功返回实际写入字节数;失败返回‑1。

注意:实际写入字节数 ≤ count,不一定全部写完,代码需要处理返回值。

4.read 从文件读取数据

#include <unistd.h>

ssize_t read(int fd, void *buf, size_t count);

  • fd:文件描述符

  • buf:存放读取数据的缓冲区地址

  • count:希望读取的字节数

  • 返回:成功返回实际读到字节;读到文件末尾返回 0 ;失败返回‑1。

⚠高频易错:判断文件结束条件是返回值等于0,不能靠buf内容判断。

5.lseek 文件读写位置偏移

#include <unistd.h>

off_t lseek(int fd, off_t offset, int whence);

功能:修改文件读写指针位置,可实现文件空洞。

  • offset:偏移量,正数向后偏移,负数向前偏移

  • whence:偏移基准位置

  • SEEK_SET :从文件开头偏移

  • SEEK_CUR :从当前读写位置偏移

  • SEEK_END :从文件末尾偏移

  • 返回:成功返回当前读写位置距离文件开头的偏移字节;失败返回‑1。

三、文件IO vs 标准IO(C库)

对比维度 文件IO(系统调用 open/read) 标准IO库(fopen/fprintf)

操作对象 int 文件描述符 fd FILE* 文件流指针

实现来源 内核系统调用 C库函数,底层封装系统调用

缓冲区 无用户态缓冲区,内核存在页缓存 自带用户态缓冲区,减少系统调用次数

跨平台 Linux/Unix专用,可移植差 ANSI C标准,Windows/Linux通用

适用场景 嵌入式底层、设备文件、管道、套接字 普通文本文件、上层业务开发(CSDN博...)

四、标准IO缓冲区分类

标准IO有三类缓冲区,缓冲区刷新是面试高频考点:

  1. 行缓冲(默认1KB):终端交互使用;遇到 \n 换行、程序结束、fflush刷新缓冲区。

  2. 全缓冲(默认4KB):普通文件;缓冲区写满、程序结束、文件关闭、fflush才刷新。

  3. 无缓冲:stderr标准错误,数据直接输出,不做缓冲。

fflush(FILE* stream) :强制刷新用户态缓冲区,把缓冲区数据下发到底层系统调用。

五、格式化字符串函数

//输出到文件流

int fprintf(FILE *stream, const char *format, ...);

//输出到文件描述符(标准IO扩展)

int dprintf(int fd, const char *format, ...);

//输出到字符数组缓冲区

int sprintf(char *str, const char *format, ...);

  • sprintf :把数字、结构体数据格式化为字符串存入字符数组,用于字符串拼接。

安全问题:sprintf不检查数组越界,工程优先使用 snprintf 。

strtok字符串分割

char *strtok(char *str, const char *delim);

功能:字符串分割函数,按照分隔符截取子串。

坑点:strtok会修改原字符串,不可传入字符串常量。

🎯小结

  1. 文件IO是Linux内核提供系统调用,核心 open/read/write/close/lseek ,操作对象是文件描述符fd。

  2. 文件描述符遵循最小未使用分配原则,0/1/2默认对应标准输入输出错误;打开文件必须close,防止fd泄漏。

  3. open的flags标志位使用或运算 | 组合;mode权限仅O_CREAT创建文件时生效。

  4. read返回0代表读到文件末尾,write返回实际写入字节,不要忽略返回值。

  5. 文件IO无用户缓冲区;标准IO库自带缓冲区,分行缓冲、全缓冲、无缓冲三类,理解缓冲区刷新时机。

  6. 标准IO底层调用文件IO;嵌入式底层开发经常直接使用文件IO系统调用。

相关推荐
Rabitebla1 小时前
【Linux】进程控制(十二) 自定义 Shell(二):内建命令与进程工作目录管理
linux·c++·笔记·学习·bash
火云代理1 小时前
更换网络后为什么会退出登录?分清 IP、Cookie 与会话的关系
服务器·网络·网络协议·tcp/ip·php·ip
威嵌神州2 小时前
嵌入式排故实录:高并发下串口数据“超时丢包”的根因剖析与架构优化
运维·服务器·嵌入式硬件·缓存
budingxiaomoli2 小时前
Spring统一功能处理
java·后端·spring
Flynn Liang4 小时前
可观测性与成本治理:一次对话的 17 个观测点
java·langchain·可观测性·micrometer·langchain4j·token 成本·llm 监控
金銀銅鐵4 小时前
带您看懂字节码指令(三):同一行加法,为什么有四种指令
java·jvm
火云代理5 小时前
同一个网站,有的网络能打开、有的打不开?认识 IPv4 与 IPv6 的访问差异
服务器·网络·网络协议·tcp/ip·测试工具·php·状态模式
坤坤子吖5 小时前
Linux网络编程:TCP 粘包与半包问题,如何正确处理 TCP 流式数据?
linux·服务器·网络·笔记·网络协议·学习
AI_Gump6 小时前
Harness篇|DeepSeek Harness 上手机:五条安卓移植路线与 App 内 Linux 拆解
android·linux·人工智能·智能手机·deepseek
星恒随风7 小时前
MySQL 从零入门(六):复合查询详解——多表查询、自连接、子查询与 UNION
linux·服务器·数据库·mysql