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

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 应用编程中最基础的知识&#xff0c;即文件 I/O&#xff08;Input、Outout…...

【信息系统项目管理师】高分论文:论信息系统项目的风险管理(人民医院的信息系统)

更多内容请见: 备考信息系统项目管理师-专栏介绍和目录 文章目录 论文1、规划风险管理2、项目风险识别3、风险定性分析4、风险定量分析5、制定风险应对6、实施风险应对计划7、监督风险论文 2022年6月,我作为项目经理承担了XX县人民医院的信息系统建设,该项目总投资300万,其…...

UE播放声音

蓝图中有两个播放声音的函数 Play Sound 2D 和 Play Sound at Location Play Sound 2D没有声音距离衰减&#xff0c;一般用于界面ui Play Sound at Location 有声音距离衰减&#xff0c;一般用于枪声&#xff0c;场景声等&#xff0c;比较常用...

Docker Compose 启动 Harbor 并指定网络

1. 介绍 Harbor 是一个开源的企业级 Docker 镜像仓库&#xff0c;提供镜像存储、访问控制、安全扫描等功能。使用 Docker Compose 启动 Harbor 时&#xff0c;您可以指定一个自定义网络&#xff0c;以便管理容器之间的网络通信。在本示例中&#xff0c;我们将创建一个名为 har…...

WebSocket 实战案例:从设计到部署

在前六篇文章中,我们深入探讨了 WebSocket 的基础原理、服务端开发、客户端实现、安全实践、性能优化和测试调试。今天,让我们通过一个实战案例,看看如何将这些知识应用到实际项目中。我曾在一个大型在线教育平台中,通过 WebSocket 实现了实时互动课堂,支持了数万名师生的同时在…...

selenium合集

环境搭建步骤 安装selenium pip install selenium 安装浏览器 安装浏览器驱动 谷歌浏览器&#xff1a;chromdriver.exe ie浏览器:ieserverdriver.exe FireFox浏览器:geckodriver.exe 特别注意⚠️&#xff1a;下载驱动版本必须与浏览器版本一致 下载地址 淘宝镜像&#xff1…...

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 主从数据库之间的数据同步 在实际项目中&#xff0c;为了提高 系统的读性能 和 数据的可用性&#xff0c;通常会使用 主从数据库架构。Spring Boot 提供了对 多数据源 的良好支持&#xff0c;可以轻松配置 主从数据库 的数据同步&#xff0c;实现…...

【小程序开发】- 小程序版本迭代指南(版本发布教程)

一&#xff0c;版本号 版本号是小程序版本的标识&#xff0c;通常由一系列数字组成&#xff0c;如 1.0.0、1.1.0 等。版本号的格式通常是 主版本号.次版本号.修订号 主版本号&#xff1a;当小程序有重大更新或不兼容的更改时&#xff0c;主版本号会增加。 次版本号&#xff1a…...

MySQL 间隙锁避免“可重复读”出现“幻读”

在数据库事务处理中&#xff0c;可重复读&#xff08;Repeatable Read&#xff09;是一个常用的隔离级别&#xff0c;但其默认行为可能导致幻读现象。然而&#xff0c;在 MySQL 的实现中&#xff0c;通过 **间隙锁&#xff08;Gap Lock&#xff09;**机制&#xff0c;能够避免幻…...

揭秘区块链隐私黑科技:零知识证明如何改变未来

文章目录 1. 引言&#xff1a;什么是零知识证明&#xff1f;2. 零知识证明的核心概念与三大属性2.1 完备性&#xff08;Completeness&#xff09;2.2 可靠性&#xff08;Soundness&#xff09;2.3 零知识性&#xff08;Zero-Knowledge&#xff09; 3. 零知识证明的工作原理4. 零…...

JavaWeb开发:从入门到精通

近年来&#xff0c;JavaWeb开发已经成为了互联网开发领域的重要技术之一。无论是大型企业还是个人项目&#xff0c;都离不开JavaWeb开发。本文将为您介绍JavaWeb开发的基本概念、常用技术和开发流程&#xff0c;帮助您快速入门并掌握这一技术。 一、JavaWeb开发的基本概念 Jav…...

2025年01月07日Github流行趋势

项目名称&#xff1a;khoj 项目地址url&#xff1a;https://github.com/khoj-ai/khoj项目语言&#xff1a;Python历史star数&#xff1a;20105今日star数&#xff1a;363项目维护者&#xff1a;debanjum, sabaimran, MythicalCow, aam-at, shantanuSakpal项目简介&#xff1a;你…...

c#集成npoi根据excel模板导出excel

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

Vue2移动端(H5项目)项目封装switch组件支持动态设置开启关闭背景色、值及组件内显示文字描述、禁用、switch 的宽度

前言 近期产品需求&#xff1a;Vue2移动端项目需要在switch开关内显示文字&#xff0c;看Vantui没有对应功能&#xff0c;因此自己手撸写了这个组件。 一、最终效果 二、参数配置 1、代码示例&#xff1a; <t-switch v-model"check"/>2、配置参数&#xff08;…...

MATLAB语言的语法糖

MATLAB语言的语法糖 引言 在编程语言的发展历程中&#xff0c;语法糖&#xff08;Syntactic Sugar&#xff09;被广泛提及。它指的是一种编程语言的语法特性&#xff0c;旨在使代码更易读、更易写&#xff0c;虽然这些特性并不增加语言的表达能力&#xff0c;但能使程序员的生…...

数字IC设计高频面试题

在数字IC设计领域&#xff0c;面试是评估候选人技术能力和问题解决能力的重要环节。数字IC设计的复杂性和要求在不断提高。面试官通常会提出一系列面试题&#xff0c;以考察应聘者在数字设计、验证、时钟管理、功耗优化等方面的专业知识和实践经验。 这些题目不仅涉及理论知识…...

OpenCV 4.5至4.10版本更新概述

OpenCV 4.5至4.10版本更新概述 OpenCV 从 4.5 到 4.10 版本的更迭中&#xff0c;每个版本都引入了新功能、优化和修复。以下是主要版本的更新内容概述&#xff1a; OpenCV 4.5.x 系列 4.5.0 (2020年10月) 新增对 YOLOv4 的支持。引入 DNN 模块的改进&#xff0c;包括对 ONNX …...

OSPF - LSA对照表

LSA的三要素&#xff0c;如何唯一表示一条LSA  Type&#xff1a;表示是几类的LSA  Link-id&#xff1a;这个比较特殊&#xff0c;不同的LSA的Link-ID不同  Advertising router&#xff1a;谁产生的LSA 常用的就是1、2、3、4、5、7型LSA 点击蓝字跳转LSA详细介绍(持续更新中…...

游戏引擎学习第77天

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

2025年能源电力系统与流体力学国际会议 (EPSFD 2025)

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

基于Flask实现的医疗保险欺诈识别监测模型

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

vscode(仍待补充)

写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh&#xff1f; 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; }//解释这串代码&#xff0c;写上注释 当然可以&#xff01;这段代码是 Qt …...

LeetCode - 394. 字符串解码

题目 394. 字符串解码 - 力扣&#xff08;LeetCode&#xff09; 思路 使用两个栈&#xff1a;一个存储重复次数&#xff0c;一个存储字符串 遍历输入字符串&#xff1a; 数字处理&#xff1a;遇到数字时&#xff0c;累积计算重复次数左括号处理&#xff1a;保存当前状态&a…...

Qt Http Server模块功能及架构

Qt Http Server 是 Qt 6.0 中引入的一个新模块&#xff0c;它提供了一个轻量级的 HTTP 服务器实现&#xff0c;主要用于构建基于 HTTP 的应用程序和服务。 功能介绍&#xff1a; 主要功能 HTTP服务器功能&#xff1a; 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...

让AI看见世界:MCP协议与服务器的工作原理

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

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

&#x1f680; C extern 关键字深度解析&#xff1a;跨文件编程的终极指南 &#x1f4c5; 更新时间&#xff1a;2025年6月5日 &#x1f3f7;️ 标签&#xff1a;C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言&#x1f525;一、extern 是什么&#xff1f;&…...

【HTTP三个基础问题】

面试官您好&#xff01;HTTP是超文本传输协议&#xff0c;是互联网上客户端和服务器之间传输超文本数据&#xff08;比如文字、图片、音频、视频等&#xff09;的核心协议&#xff0c;当前互联网应用最广泛的版本是HTTP1.1&#xff0c;它基于经典的C/S模型&#xff0c;也就是客…...

什么是Ansible Jinja2

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