Linux C编程——文件IO基础
文件IO基础
- 一、简单的文件 IO 示例
- 二、文件描述符
- 三、open 打开文件
- 1. 函数原型
- 2. 文件权限
- 3. 宏定义文件权限
- 4. 函数使用实例
- 四、write 写文件
- 五、read 读文件
- 六、close 关闭文件
- 七、Iseek
绍 Linux 应用编程中最基础的知识,即文件 I/O(Input、Outout)
一、简单的文件 IO 示例
一个通用的 IO 模型通常包括打开文件、读写文件、关闭文件这些基本操作,主要涉及到 4 个函数:open()、read()、write()以及 close()。
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(void)
{char buff[1024];int fd1, fd2;int ret;/* 打开源文件 src_file(只读方式) */fd1 = open("./src_file", O_RDONLY);if (-1 == fd1)return fd1;/* 打开目标文件 dest_file(只写方式) */fd2 = open("./dest_file", O_WRONLY);if (-1 == fd2) {ret = fd2;goto out1;}/* 读取源文件 1KB 数据到 buff 中 */ret = read(fd1, buff, sizeof(buff));if (-1 == ret)goto out2;/* 将 buff 中的数据写入目标文件 */ret = write(fd2, buff, sizeof(buff));if (-1 == ret)goto out2;ret = 0;
out2:/* 关闭目标文件 */close(fd2);
out1:/* 关闭源文件 */close(fd1);return ret;
}
该代码主要实现:
- 从源码文件 src_file 中读取 1KB 数据
- 将读取的数据写入 dest_file 中
读写操作前,首先调用 open 函数将 源文件 和 目标文件 打开,成功打开之后再调用 read 函数从源文件中读取 1KB 数据,然后再调用 write 函数将这 1KB 数据写入目标文件中。读写操作完成之后,最后调用 close 函数关闭源文件和目标文件。
二、文件描述符
看上面代码中的 open 函数会有一个返回值。然后会赋值给 fd 中,这是一个 int 类型数据,在 open 函数执行成功的情况下,会返回一个非负函数,而这个返回值就是一个文件描述符。对 Linux 内核,所有打开的文件都会通过文件描述符进行索引。
当调用 open 函数打开一个现有文件或创建一个新文件时,内核会向进程返回一个文件描述符,用于指代被打开的文件,所有执行 IO 操作的系统调用都是通过文件描述符来索引到对应的文件。当调用 read/write 函数进行文件读写时,会将文件描述符传送给 read/write 函数,所以在代码中,fd1 就是源文件 src_file 被打开时所对应的文件描述符,而 fd2 则是目标文件 dest_file 被打开时所对应的文件描述符。
在 Linux 系统下,我们可以通过 ulimit 命令来查看进程可打开的最大文件数,用法如下所示:
ulimit -n
当我们在程序中,调用 open 函数打开文件的时候,分配的文件描述符一般都是从 3 开始,是 0、1、2 这三个文件描述符已经默认被系统占用了,分别分配给了系统标准输入(0)、标准输出(1)以及标准错误(2)。
标准输入一般对应的是键盘,可以理解为 0 便是打开键盘对应的设备文件时所得到的文件描述符;
标准输出一般指的是 LCD 显示器,可以理解为 1 便是打开 LCD 设备对应的设备文件时所得到的文件描述符;
而标准错误一般指的也是 LCD 显示器。
三、open 打开文件
1. 函数原型
open 函数的函数原型为:
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
- pathname:字符串类型,用于标识需要打开或创建的文件,可以包含路径。
- flag:调用 open 函数时需要提供的标志,包括文件访问模式标志以及其它文件相关标志,这些标志使用宏定义进行描述,都是常量。
- mode:此参数用于指定新建文件的访问权限,只有当 flags 参数中包含 O_CREAT 或 O_TMPFILE 标志时才有效(O_TMPFILE 标志用于创建一个临时文件)。
flags 参数时既可以单独使用某一个标志,也可以通过位或运算(|)将多个标志进行组合:
open("./src_file", O_RDONLY) //单独使用某一个标志
open("./src_file", O_RDONLY | O_NOFOLLOW) //多个标志组合
2. 文件权限
当我们调用 open 函数去新建一个文件时,也需要指定该文件的权限,而 mode 参数便用于指定此文件的权限。首先 mode 参数的类型是 mode_t,这是一个 u32 无符号整形数据,权限表示方法如下所示:
们从低位从上看,每 3 个 bit 位分为一组,分别表示:
- O:表示其他用户的权限
- G:表示同组用户(group)的权限
- U:表示文件所属用户的权限
- S:表示文件的特殊权限
3 个 bit 位中,按照 rwx 顺序来分配权限位(特殊权限除外)。
- 最高位(权值为 4)表示读权限,为 1 时表示具有读权限,为 0 时没有读权限。
- 中间位(权值为 2)表示写权限,为 1 时表示具有写权限,为 0 时没有写权限。
- 最低位(权值为 1)表示执行权限,为 1 时表示具有可执行权限,为 0 时没有执行权限。
对于最高权限:
1FF(hex)、111 111 111(bin)、777(oct)、511(dec)
几个权限例子:
111 000 000:表示文件所属者拥有 读、写、执行权限。而同组用户和其他用户并不具有任何权限。
100 100 100:表示三类都有 读权限,但没有 写、执行权限。
3. 宏定义文件权限
在实际编程中,我们可以直接使用 Linux 中已经定义好的宏,不同的宏定义表示不同的权限。而宏定义其实可以根据英文来判断是什么权限。以下是几个例子:
USR文件所属者
S_IRUSR
:IR读权限、
S_IWUSR
:IW写权限
S_IXUSR
:IX执行权限
S_IRWXU
:RWX 读、写、执行权限。U代表USR
GRP同组用户和OTH其他用户就不介绍了,一个道理。
4. 函数使用实例
使用 open 函数打开一个已经存在的文件,使用只读方式打开:
int fd = open("./app.c",O_RDONLY)
if(-1==fd)return fd;
使用 open 函数打开一个指定的文件,使用可读可写方式,如果该文件是一个符号链接文件,则不对其进行解引用,直接返回错误:
int fd = open("/home/prover/hello",O_RDWR|O_NOFOLLOW);
if(-1==fd)return fd;
使用 open 函数打开一个指定的文件,如果该文件不存在则创建该文件,创建该文件时,将文件权限设置如下:
- 文件所属者拥有读、写、执行权限;
- 同组用户与其他用户只有读权限
- 使用可读可写方式打开:
int fd = open("/home/prover/hello",O_RDWR|O_CREAT,S_IRWXU|S_IRGRP|S_IROTH);
if(-1==fd)return fd;
四、write 写文件
函数原型
ssize_t write(int fd, const void *buf, size_t count);
- fd:文件描述符
- buf:指定写入数据对应的缓冲区
- count:指定写入的字节数
- 返回值:如果成功将返回写入的字节数。如果此数字小于 count 参数,这不是错误,譬如磁盘空间已满,可能会发生这种情况;如果写入出错,则返回-1。
对于普通文件,默认情况下当前位置偏移量一般是 0,也就是指向了文件起始位置,当调用 read、write 函数读写操作完成之后,当前位置偏移量也会向后移动对应字节数。
隔壁 CTF 的 Pwn 二进制安全,可以利用 write() 函数进行漏洞利用,填充缓冲区,填入 system 函数地址和 /bin/sh 的地址,从而达到漏洞利用。
五、read 读文件
函数原型
ssize_t read(int fd, void *buf, size_t count);
- fd:文件描述符。与 write 函数的 fd 参数意义相同。
- buf:指定用于存储读取数据的缓冲区。
- count:指定需要读取的字节数。
- 返回值
- 如果读取成功将返回读取到的字节数,实际读取到的字节数可能会小于 count 参数指定的字节数。
- 也有可能会为 0,譬如进行读操作时,当前文件位置偏移量已经到了文件末尾。
- 实际读取到的字节数少于要求读取的字节数,譬如在到达文件末尾之前有 30 个字节数据,而要求读取 100 个字节,则 read 读取成功只能返回 30;而下一次再调用 read 读,它将返回 0(文件末尾)。
六、close 关闭文件
函数原型
int close(int fd);
- fd:文件描述符,需要关闭的文件所对应的文件描述符。
- 返回值:如果成功返回 0,如果失败则返回-1。
除了使用 close 函数显式关闭文件之外,在 Linux 系统中,当一个进程终止时,内核会自动关闭它打开的所有文件,也就是说在我们的程序中打开了文件,如果程序终止退出时没有关闭打开的文件,那么内核会自动将程序中打开的文件关闭。很多程序都利用了这一功能而不显式地用 close 关闭打开的文件。
七、Iseek
上面说到,对于每个打开的文件,系统都会记录它的读写位置偏移量,我们也把这个读写位置偏移量称为读写偏移量,记录了文件当前的读写位置,当调用 read()或 write()函数对文件进行读写操作时,就会从当前读写位置偏移量开始进行数据读写。
读写偏移量用于指示 read()或 write()函数操作时文件的起始位置,会以相对于文件头部的位置偏移量来表示,文件第一个字节数据的位置偏移量为 0。
当打开文件时,会将读写偏移量设置为指向文件开始位置处,以后每次调用 read()、write()将自动对其进行调整,以指向已读或已写数据后的下一字节,因此,连续的调用 read()和 write()函数将使得读写按顺序递增,对文件进行操作。
函数原型
off_t lseek(int fd, off_t offset, int whence);
- fd:文件描述符。
- offset:偏移量,以字节为单位。
- whence:用于定义参数 offset 偏移量对应的参考值。
- SEEK_SET:读写偏移量将指向 offset 字节位置处(从文件头部开始算);
- SEEK_CUR:读写偏移量将指向当前位置偏移量 + offset 字节位置处,offset 可以为正、也可以为负,如果是正数表示往后偏移,如果是负数则表示往前偏移;
- SEEK_END:读写偏移量将指向文件末尾 + offset 字节位置处,同样 offset 可以为正、也可以为负,如果是正数表示往后偏移、如果是负数则表示往前偏移。
- 返回值:成功将返回从文件头部开始算起的位置偏移量(字节为单位),也就是当前的读写位置;发生错误将返回-1。
使用示例
将读写位置移动到文件开头处:
off_t off = lseek(fd,0,SEEK_SET);
if(-1==off)return -1;
将读写位置移动到文件末尾:
off_t off = lseek(fd,0,SEEK_END);
if(-1==off)return -1;
将读写位置移动到偏移文件开头 100 个字节处:
off_t off = lseek(fd,100,SEEK_SET);
if(-1==off)return -1;
获取当前读写位置偏移量
off_t off = lseek(fd,0,SEEK_CUR);
if(-1==off)return -1;
相关文章:

Linux C编程——文件IO基础
文件IO基础 一、简单的文件 IO 示例二、文件描述符三、open 打开文件1. 函数原型2. 文件权限3. 宏定义文件权限4. 函数使用实例 四、write 写文件五、read 读文件六、close 关闭文件七、Iseek 绍 Linux 应用编程中最基础的知识,即文件 I/O(Input、Outout…...
【信息系统项目管理师】高分论文:论信息系统项目的风险管理(人民医院的信息系统)
更多内容请见: 备考信息系统项目管理师-专栏介绍和目录 文章目录 论文1、规划风险管理2、项目风险识别3、风险定性分析4、风险定量分析5、制定风险应对6、实施风险应对计划7、监督风险论文 2022年6月,我作为项目经理承担了XX县人民医院的信息系统建设,该项目总投资300万,其…...

UE播放声音
蓝图中有两个播放声音的函数 Play Sound 2D 和 Play Sound at Location Play Sound 2D没有声音距离衰减,一般用于界面ui Play Sound at Location 有声音距离衰减,一般用于枪声,场景声等,比较常用...
Docker Compose 启动 Harbor 并指定网络
1. 介绍 Harbor 是一个开源的企业级 Docker 镜像仓库,提供镜像存储、访问控制、安全扫描等功能。使用 Docker Compose 启动 Harbor 时,您可以指定一个自定义网络,以便管理容器之间的网络通信。在本示例中,我们将创建一个名为 har…...
WebSocket 实战案例:从设计到部署
在前六篇文章中,我们深入探讨了 WebSocket 的基础原理、服务端开发、客户端实现、安全实践、性能优化和测试调试。今天,让我们通过一个实战案例,看看如何将这些知识应用到实际项目中。我曾在一个大型在线教育平台中,通过 WebSocket 实现了实时互动课堂,支持了数万名师生的同时在…...
selenium合集
环境搭建步骤 安装selenium pip install selenium 安装浏览器 安装浏览器驱动 谷歌浏览器:chromdriver.exe ie浏览器:ieserverdriver.exe FireFox浏览器:geckodriver.exe 特别注意⚠️:下载驱动版本必须与浏览器版本一致 下载地址 淘宝镜像࿱…...
JVM生产环境常用参数配置及调优建议
一、生产常用参数配置 JAVA_OPTS"-server -Xms3000m -Xmx3000m -Xmn1500m -XX:UseG1GC -XX:ConcGCThreads8 -XX:PrintGCDetails -XX:PrintGCTimeStamps -Xloggc:./g1-gc.log -XX:MaxMetaspaceSize256m -XX:-UseGCOverheadLimit -XX:UseCompressedOops -XX:HeapDumpOnOu…...
Spring Boot 3 实现 MySQL 主从数据库之间的数据同步
✅ Spring Boot 3 实现 MySQL 主从数据库之间的数据同步 在实际项目中,为了提高 系统的读性能 和 数据的可用性,通常会使用 主从数据库架构。Spring Boot 提供了对 多数据源 的良好支持,可以轻松配置 主从数据库 的数据同步,实现…...

【小程序开发】- 小程序版本迭代指南(版本发布教程)
一,版本号 版本号是小程序版本的标识,通常由一系列数字组成,如 1.0.0、1.1.0 等。版本号的格式通常是 主版本号.次版本号.修订号 主版本号:当小程序有重大更新或不兼容的更改时,主版本号会增加。 次版本号:…...
MySQL 间隙锁避免“可重复读”出现“幻读”
在数据库事务处理中,可重复读(Repeatable Read)是一个常用的隔离级别,但其默认行为可能导致幻读现象。然而,在 MySQL 的实现中,通过 **间隙锁(Gap Lock)**机制,能够避免幻…...

揭秘区块链隐私黑科技:零知识证明如何改变未来
文章目录 1. 引言:什么是零知识证明?2. 零知识证明的核心概念与三大属性2.1 完备性(Completeness)2.2 可靠性(Soundness)2.3 零知识性(Zero-Knowledge) 3. 零知识证明的工作原理4. 零…...
JavaWeb开发:从入门到精通
近年来,JavaWeb开发已经成为了互联网开发领域的重要技术之一。无论是大型企业还是个人项目,都离不开JavaWeb开发。本文将为您介绍JavaWeb开发的基本概念、常用技术和开发流程,帮助您快速入门并掌握这一技术。 一、JavaWeb开发的基本概念 Jav…...

2025年01月07日Github流行趋势
项目名称:khoj 项目地址url:https://github.com/khoj-ai/khoj项目语言:Python历史star数:20105今日star数:363项目维护者:debanjum, sabaimran, MythicalCow, aam-at, shantanuSakpal项目简介:你…...

c#集成npoi根据excel模板导出excel
NuGet中安装npoi 创建excel模板,替换其中的内容生成新的excel文件。 例子中主要写了这四种情况: 1、替换单个单元格内容; 2、替换横向多个单元格; 3、替换表格; 4、单元格中插入图片; using System.IO; …...

Vue2移动端(H5项目)项目封装switch组件支持动态设置开启关闭背景色、值及组件内显示文字描述、禁用、switch 的宽度
前言 近期产品需求:Vue2移动端项目需要在switch开关内显示文字,看Vantui没有对应功能,因此自己手撸写了这个组件。 一、最终效果 二、参数配置 1、代码示例: <t-switch v-model"check"/>2、配置参数(…...
MATLAB语言的语法糖
MATLAB语言的语法糖 引言 在编程语言的发展历程中,语法糖(Syntactic Sugar)被广泛提及。它指的是一种编程语言的语法特性,旨在使代码更易读、更易写,虽然这些特性并不增加语言的表达能力,但能使程序员的生…...

数字IC设计高频面试题
在数字IC设计领域,面试是评估候选人技术能力和问题解决能力的重要环节。数字IC设计的复杂性和要求在不断提高。面试官通常会提出一系列面试题,以考察应聘者在数字设计、验证、时钟管理、功耗优化等方面的专业知识和实践经验。 这些题目不仅涉及理论知识…...
OpenCV 4.5至4.10版本更新概述
OpenCV 4.5至4.10版本更新概述 OpenCV 从 4.5 到 4.10 版本的更迭中,每个版本都引入了新功能、优化和修复。以下是主要版本的更新内容概述: OpenCV 4.5.x 系列 4.5.0 (2020年10月) 新增对 YOLOv4 的支持。引入 DNN 模块的改进,包括对 ONNX …...
OSPF - LSA对照表
LSA的三要素,如何唯一表示一条LSA Type:表示是几类的LSA Link-id:这个比较特殊,不同的LSA的Link-ID不同 Advertising router:谁产生的LSA 常用的就是1、2、3、4、5、7型LSA 点击蓝字跳转LSA详细介绍(持续更新中…...

游戏引擎学习第77天
仓库: https://gitee.com/mrxiao_com/2d_game 回顾昨天的 bug 今天我们继续开发进度,进行调试昨天代码的问题,主要是关于如何跟踪玩家和敌人在世界中的高度位置。虽然我们做的是一款 2D 游戏,但我们希望能够处理多层的房间,玩家…...

2025年能源电力系统与流体力学国际会议 (EPSFD 2025)
2025年能源电力系统与流体力学国际会议(EPSFD 2025)将于本年度在美丽的杭州盛大召开。作为全球能源、电力系统以及流体力学领域的顶级盛会,EPSFD 2025旨在为来自世界各地的科学家、工程师和研究人员提供一个展示最新研究成果、分享实践经验及…...

基于Flask实现的医疗保险欺诈识别监测模型
基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施,由雇主和个人按一定比例缴纳保险费,建立社会医疗保险基金,支付雇员医疗费用的一种医疗保险制度, 它是促进社会文明和进步的…...

vscode(仍待补充)
写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh? debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...

LeetCode - 394. 字符串解码
题目 394. 字符串解码 - 力扣(LeetCode) 思路 使用两个栈:一个存储重复次数,一个存储字符串 遍历输入字符串: 数字处理:遇到数字时,累积计算重复次数左括号处理:保存当前状态&a…...
Qt Http Server模块功能及架构
Qt Http Server 是 Qt 6.0 中引入的一个新模块,它提供了一个轻量级的 HTTP 服务器实现,主要用于构建基于 HTTP 的应用程序和服务。 功能介绍: 主要功能 HTTP服务器功能: 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...

让AI看见世界:MCP协议与服务器的工作原理
让AI看见世界:MCP协议与服务器的工作原理 MCP(Model Context Protocol)是一种创新的通信协议,旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天,MCP正成为连接AI与现实世界的重要桥梁。…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南
🚀 C extern 关键字深度解析:跨文件编程的终极指南 📅 更新时间:2025年6月5日 🏷️ 标签:C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言🔥一、extern 是什么?&…...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...

什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...