当前位置: 首页 > news >正文

Linux 系统编程 - 文件IO

目录

文件描述符

文件操作的步骤

(一)打开 -- open系统调用

1. 函数原型

2. 参数详解

3. 返回值

4. 主要 flags参数详解

(二)读文件 -- read

1.函数原型

2. 参数详解

3. 返回值详解

(三)写入文件 -- write

1. 函数原型

2. 参数详解

3. 返回值详解

(四)文件定位 -- lseek函数

1. 函数原型

2. 功能

3. 参数详解

4. whence参数

5. 返回值详解

6. 关键特性和用法

核心使用要点与注意事项


系统调用,操作系统为了方便用户使用系统功能而对外提供的一组系统函数。关于文件操作的相关函数叫文件io

C库函数,c标准库函数,c语言程序能够运行的地址,默认c库函数都可以调用。 关于文件操作的相关函数叫标准io

标准io和文件io关系

文件描述符

定义:文件描述符是一个非负整数,是 Linux 内核用来标识进程打开文件的索引。可以把它理解为文件在特定进程内的“代号”或“编号”。

核心特点

  1. 进程私有:每个进程都有自己独立的文件描述符表,用于管理本进程打开的所有文件。

  2. 分配规则:文件描述符从0开始顺序分配。

  3. 标准描述符012是系统为每个进程预留的三个标准描述符,通常关联到终端:

    • 0​ -STDIN_FILENO:标准输入,默认为键盘。

    • 1​ -STDOUT_FILENO:标准输出,默认为屏幕。

    • 2​ -STDERR_FILENO:标准错误输出,默认为屏幕。

  4. 新文件描述符:新打开的文件,其描述符3开始分配

文件操作的步骤

(一)打开 --open系统调用

1. 函数原型

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

2. 参数详解

参数

含义

说明

pathname

文件路径

需要打开或创建的文件路径(字符串)。

flags

打开标志

控制文件的打开/创建方式。多个标志用按位或 (\|)​ 组合。

mode

权限模式

指定新创建文件的访问权限(八进制数,如0644),仅在flags包含O_CREAT时有效。

3. 返回值

情况

返回值

成功

返回一个非负整数,即新打开文件的文件描述符

失败

返回-1,并设置全局变量errno以指示具体错误。

4. 主要flags参数详解

flags参数用于指定文件的打开方式,是控制open行为的关键

man fopen可以查到这张表

标志

名称

功能与影响

O_RDONLY

只读打开

文件只能用于读取,不能写入。

O_WRONLY

只写打开

文件只能用于写入,不能读取。

O_RDWR

读写打开

文件既可以读取也可以写入

O_CREAT

创建文件

如果pathname指定的文件不存在,则创建它。需要配合mode参数

O_TRUNC

截断文件

如果文件已存在且以可写方式 (O_WRONLYO_RDWR) 打开,则将其长度截断为0(清空内容)。

O_APPEND

追加模式

每次执行write操作时,文件偏移量会自动移动到文件末尾,保证写入的内容总是被追加到文件尾部。

组合使用示例

  • open(“file.txt”, O_RDONLY);// 以只读方式打开已存在的文件

  • open(“log.txt”, O_WRONLY \| O_CREAT \| O_APPEND, 0644);// 以只写、追加模式打开文件,不存在则创建,权限为rw-r--r--

  • open(“temp.dat”, O_RDWR \| O_CREAT \| O_TRUNC, 0666);// 以读写方式打开文件,不存在则创建,存在则清空,权限为rw-rw-rw-

(二)读文件 -- read

1.函数原型

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

2. 参数详解

参数

数据类型

含义与说明

fd

int

文件描述符,标识要读取的已打开文件。

buf

void *

缓冲区指针,指向一片用户空间的内存区域,用于存放从文件中读取到的数据。

count

size_t

请求读取的字节数,表示本次希望从文件中最多读取多少个字节到buf中。

3. 返回值详解

返回值

含义与说明

> 0

成功,返回实际读取到的字节数。此值可能小于count参数,原因包括:文件剩余字节不足、从管道或终端读取、被信号中断等。

= 0

表示已到达文件末尾,没有更多数据可读。

-1

失败,表示发生了错误。此时会设置全局变量errno以指示具体错误原因(如EINTR被信号中断,EBADF文件描述符无效等)。


(三)写入文件 -- write

1. 函数原型

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

2. 参数详解

参数

数据类型

含义与说明

fd

int

文件描述符,标识要写入的已打开文件。

buf

const void *

数据缓冲区指针,指向一片用户空间的内存区域,其中包含要写入文件的数据。

count

size_t

请求写入的字节数,表示希望从buf中取出多少个字节写入文件。

3. 返回值详解

返回值

含义与说明

> 0

成功,返回实际写入的字节数。在大多数情况下,此值等于count。但如果磁盘空间不足、写入被信号中断、或遇到资源限制(如 RLIMIT_FSIZE),此值可能小于count

= 0

通常表示没有写入任何数据。对于普通文件,这很少见;但对于某些特殊文件(如管道、套接字)可能存在。

-1

失败,表示发生了错误。此时会设置全局变量errno以指示具体错误原因(如EINTR被信号中断,ENOSPC设备无剩余空间,EBADF文件描述符无效等)。

实现cp功能

#include <stdio.h> #include <unistd.h> #include <fcntl.h> int main(int argc, const char *argv[]) { if(argc != 3) { printf("%s <filename> <filename>\n",argv[0]); return -1; } int fd = open(argv[1],O_RDONLY|O_CREAT,0666); int fd2 = open(argv[2],O_WRONLY|O_CREAT,0666); if(fd < 0 || fd2 <0) { perror("open fail"); return -1; } char buf[1024]; int ret =0; while((ret = read(fd,buf,sizeof(buf)))!=0) { //buf[ret] = '\0'; // 添加字符串结束符 //printf("ret = %d buf = %s\n", ret, buf); write(fd2,buf,ret); } return 0; }

(四)文件定位 --lseek函数

1. 函数原型

#include <unistd.h> #include <sys/types.h> off_t lseek(int fd, off_t offset, int whence);

2. 功能

用于移动文件的读写位置指针,实现随机访问。可以读取或写入文件的任意位置,而不仅限于顺序从头到尾。

3. 参数详解

参数

数据类型

含义与说明

fd

int

文件描述符,标识已打开、可定位的文件。

offset

off_t

偏移量,表示相对于whence指定起点的移动字节数。
-正值:向文件末尾方向移动(向后)。
-负值:向文件开头方向移动(向前)。

whence

int

起始位置参考点。决定offset的计算基准,是一个整型常量

4.whence参数

whence参数通常由以下三个宏定义指定,它们是整数常量,决定了偏移的起点。

宏常量

值(常见)

含义与计算基准

SEEK_SET

0

文件开头。从文件开始位置计算偏移。新的偏移量 =offset

SEEK_CUR

1

当前位置。从当前读写指针位置计算偏移。新的偏移量 = 当前偏移 +offset

SEEK_END

2

文件末尾。从文件结束位置计算偏移。新的偏移量 = 文件大小 +offset

5. 返回值详解

返回值

含义与说明

>= 0

成功,返回移动后新的文件偏移量(从文件开头算起的字节数)。

(off_t)-1

失败,返回-1并设置errno以指示错误(如EBADF描述符无效,ESPIPE文件不支持定位)。

重要提示:返回值是新的偏移量,这是一个非负的、从文件开头计算的字节偏移。即使使用SEEK_CURSEEK_END并传入负的offset移动到文件开头之前,也会返回-1表示错误,而不会成功返回一个负的偏移量。

6. 关键特性和用法

特性/用法

说明与示例

获取当前偏移

off_t curr_pos = lseek(fd, 0, SEEK_CUR);
(偏移量为0,从当前位置计算,即返回当前偏移量)

移动到文件开头

lseek(fd, 0, SEEK_SET);

移动到文件末尾

off_t end_pos = lseek(fd, 0, SEEK_END);
(常用于获取文件大小,或为追加写做准备)

向前/向后移动

lseek(fd, 100, SEEK_CUR);// 从当前位置向后移动100字节
lseek(fd, -50, SEEK_CUR);// 从当前位置向前移动50字节

创建文件空洞

如果移动的位置超过了当前文件大小,然后执行write操作,会在原文件末尾和新写入位置之间形成“空洞”。这部分不占用实际磁盘块,读起来是0,但会使文件大小增加。

核心使用要点与注意事项

要点

read函数

write函数

数据流向

文件 (fd)​ →内存 (buf)

内存 (buf)​ →文件 (fd)

缓冲区管理

调用前必须确保buf指向的内存空间足够大,至少可容纳count字节。

调用前必须确保buf指向的内存区域已包含有效数据

阻塞行为

在默认阻塞模式下,如果文件中无足够数据(如从管道、终端或网络套接字读),调用会阻塞,直到有数据可读或到达文件尾。

在默认阻塞模式下,如果由于设备繁忙等原因无法立即写入(如向管道写但缓冲区满),调用会阻塞,直到可以写入。

典型用法

通常与循环结合使用,以处理“实际读取字节数小于请求字节数”的情况,确保读取完整数据。

通常也应检查返回值,在写入大型数据块时,可能需要多次调用write以确保所有数据被写入。

与标准描述符

fd可以为0(STDIN_FILENO),从标准输入读取。

fd可以为1(STDOUT_FILENO) 或2(STDERR_FILENO),分别向标准输出或标准错误输出写入。

http://www.jsqmd.com/news/562654/

相关文章:

  • Stable-Diffusion-3.5在Keil5嵌入式开发环境中的应用
  • 2026年第一季度北京奔驰大G新车选购指南:专业车商深度测评与推荐 - 2026年企业推荐榜
  • XXL-Job调度中心Docker版升级踩坑记:从2.3.1到最新版,这些配置项你改对了吗?
  • 河北焊接设备优质服务商盘点:旭通商贸何以成为行业信赖之选? - 2026年企业推荐榜
  • 释放Android手机潜能:告别臃肿系统的智能清理方案
  • 鼠标宏压枪技术:从需求到实战的精准射击解决方案
  • 2026金华全周期牙齿矫正优质机构推荐:金华婺城矫正牙齿/金华婺城隐形矫正/金华市区固定矫正/金华市区牙齿正畸/选择指南 - 优质品牌商家
  • 实战指南:如何用CoTracker在自定义视频上做点跟踪(从环境配置到结果可视化)
  • 嵌入式工程师必备:高效项目文档编写指南
  • 3个RVC变声器实战技巧:从环境搭建到模型优化的完整指南
  • 告别窗口混乱,迎接效率提升:Loop重新定义macOS窗口管理
  • 2026年云南垃圾房市场深度解析:五大核心服务商测评与联系指南 - 2026年企业推荐榜
  • LaTeX科技写作:OFA模型辅助论文图表描述生成
  • 2026年福州大型会议会务接待服务商综合评测与专业选型指南 - 2026年企业推荐榜
  • 智能自动化新范式:Agent-S的人机协同解决方案
  • ArcMap新手必看:Excel里的经纬度坐标,5分钟变成GIS图层(附详细截图)
  • 嵌入式系统中链表式软件定时器的实现与优化
  • ILI9341 TFT驱动库:裸机SPI显示驱动设计与优化
  • 树的“最优中心”怎么找?别再暴力试了,Minimum Height Trees 一招搞定
  • P10387 [蓝桥杯 2024 省 A] 训练士兵
  • 树莓派开机自启Python脚本:从rc.local到systemd的进阶实践
  • 重构设计流程:Grida如何提升团队300%协作效率
  • 嵌入式开发中的版本管理与编译时间戳实践
  • 数字IC后端设计入门:手把手教你用ICC完成一个RISC-V芯片的物理实现
  • 3步解放双手:崩坏星穹铁道自动化工具让资源收集效率提升200%
  • 从郭天祥老师的课到我的项目:两种裸机调度方案的实战踩坑与选型指南
  • 嵌入式系统模块通信方式:全局变量、回调函数与异步通信
  • Blender3mfFormat插件:3MF文件处理全攻略
  • Qwen3.5-27B开源模型价值:支持私有化训练微调的完整权重与LoRA接口
  • kin-openapi未来展望:OpenAPI 3.1支持与社区发展路线图