Linux C编程——文件IO基础

news2025/1/8 17:27:20

文件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;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2272737.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

论文解读 | NeurIPS'24 IRCAN:通过识别和重新加权上下文感知神经元来减轻大语言模型生成中的知识冲突...

点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入&#xff01; 点击 阅读原文 观看作者讲解回放&#xff01; 作者简介 史丹&#xff0c;天津大学博士生 内容简介 大语言模型&#xff08;LLM&#xff09;经过海量数据训练后编码了丰富的世界知识。最近的研究表明&#xff0c…

【51单片机零基础-chapter5:模块化编程】

模块化编程 将以往main中泛型的代码,放在与main平级的c文件中,在h中引用. 简化main函数 将原来main中的delay抽出 然后将delay放入单独c文件,并单独开一个delay头文件,里面放置函数的声明,相当于收纳delay的c文件里面写的函数的接口. 注意,单个c文件所有用到的变量需要在该文…

扩散模型论文概述(三):Stability AI系列工作【学习笔记】

视频链接&#xff1a;扩散模型论文概述&#xff08;三&#xff09;&#xff1a;Stability AI系列工作_哔哩哔哩_bilibili 本期视频讲的是Stability AI在图像生成的工作。 同样&#xff0c;第一张图片是神作&#xff0c;总结的太好了&#xff01; 介绍Stable Diffusion之前&…

数据库软考历年上午真题与答案解析(2018-2024)

本题考查计算机总线相关知识。 总线&#xff08;Bus&#xff09;是计算机各种功能部件之间传送信息的公共通信干线&#xff0c;它是由导线组成的传输线束。 根据总线连接设备范围的不同&#xff0c; 分为&#xff1a;1.片内总线&#xff1a;芯片内部的总线&#xff1b; 2.系统…

【three.js】模型-几何体Geometry,材质Material

模型 在现实开发中&#xff0c;有时除了需要用代码创建模型之外&#xff0c;多数场景需要加载设计师提供的使用设计软件导出的模型。此时就需要使用模型加载器去加载模型&#xff0c;不同格式的模型需要引入对应的模型加载器&#xff0c;虽然加载器不同&#xff0c;但是使用方式…

彻底学会Gradle插件版本和Gradle版本及对应关系

看完这篇&#xff0c;保你彻底学会Gradle插件版本和Gradle版本及对应关系&#xff0c;超详细超全的对应关系表 需要知道Gradle插件版本和Gradle版本的对应关系&#xff0c;其实就是需要知道Gradle插件版本对应所需的gradle最低版本&#xff0c;详细对应关系如下表格&#xff0…

预测facebook签到位置

1.11 案例2&#xff1a;预测facebook签到位置 学习目标 目标 通过Facebook位置预测案例熟练掌握第一章学习内容 1 项目描述 本次比赛的目的是预测一个人将要签到的地方。 为了本次比赛&#xff0c;Facebook创建了一个虚拟世界&#xff0c;其中包括10公里*10公里共100平方公里的…

【万字详细教程】Linux to go——装在移动硬盘里的Linux系统(Ubuntu22.04)制作流程;一口气解决系统安装引导文件迁移显卡驱动安装等问题

Linux to go制作流程 0.写在前面 关于教程Why Linux to go&#xff1f;实际效果 1.准备工具2.制作步骤 下载系统镜像硬盘分区准备启动U盘安装系统重启完成驱动安装将系统启动引导程序迁移到移动硬盘上 3.可能出现的问题 3.1.U盘引导系统安装时出现崩溃3.2.不影响硬盘里本身已有…

在 macOS 上,你可以使用系统自带的 终端(Terminal) 工具,通过 SSH 协议远程连接服务器

文章目录 1. 打开终端2. 使用 SSH 命令连接服务器3. 输入密码4. 连接成功5. 使用密钥登录&#xff08;可选&#xff09;6. 退出 SSH 连接7. 其他常用 SSH 选项8. 常见问题排查问题 1&#xff1a;连接超时问题 2&#xff1a;权限被拒绝&#xff08;Permission denied&#xff09…

Linux CentOS 7系统如何修改panel 重新打开最小化的界面/软件/程序

CentOS 7系统下&#xff0c;部分用户可能一开始打开界面没有类似Windows的下方菜单栏&#xff0c;只有一个浮动的panel。一旦打开软件&#xff0c;然后点击最小化后&#xff0c;找不到重新打开的方法。 右键panel&#xff0c;点击Add New Items… 选择以下三个基本就可以了&am…

打造三甲医院人工智能矩阵新引擎(二):医学影像大模型篇--“火眼金睛”TransUNet

一、引言 1.1 研究背景与意义 在现代医疗领域,医学影像作为疾病诊断与治疗的关键依据,发挥着不可替代的作用。从传统的X射线、CT(计算机断层扫描)到MRI(磁共振成像)等先进技术,医学影像能够直观呈现人体内部结构,为医生提供丰富的诊断信息,涵盖疾病识别、病灶定位、…

基于Arduino的FPV头部追踪相机系统

构建FPV头部追踪相机&#xff1a;让你置身于遥控车辆之中&#xff01; 在遥控车辆和模型飞行器的世界中&#xff0c;第一人称视角&#xff08;FPV&#xff09;体验一直是爱好者们追求的目标。通过FPV头部追踪相机&#xff0c;你可以像坐在车辆或飞行器内部一样&#xff0c;自由…

使用 Three.js 创建动态粒子效果

今天&#xff0c;带大家使用粒子实现一个粒子飞毯的效果&#xff0c;我们先来看一下效果。 实现 初始化场景 首先创建一个场景&#xff0c;所有 3D 对象都会被添加到这个场景中。 const scene new THREE.Scene();相机和渲染器 配置相机和渲染器来捕捉和显示场景。 相机…

Linux双端口服务器:端口1的文件系统目录挂载到端口2

目录 一、服务器安装NFS服务并配置二、文件挂载三、持久化挂载总结为什么服务器配置多个端口 目前有一台服务器&#xff0c;不过他设置了两个SSH的端口&#xff0c;通过下面方法可以让这两个端口连接的主机能够共享同一个文件系统&#xff0c;原本这两个端口的文件系统是隔离的…

机器学习算法---贝叶斯学习

1.了解相关概念 先验概率&#xff1a;有数据集d,以及假设h,此时h是不确定的。在还没有训练数据之前h的初始概率记为P(h),类似地我们把P(d)表示训练数据d在任何假设都未知或不确定时的概率。P(d|h)表示已知假设h成立时d的概率。 后验概率&#xff1a;就是在数据d上经过学习之后…

[paddle] 非线性拟合问题的训练

利用paddlepaddle建立神经网络&#xff0c;模拟有限个数据的非线性拟合 本文仍然考虑 f ( x ) sin ⁡ ( x ) x f(x)\frac{\sin(x)}{x} f(x)xsin(x)​ 函数在区间 [-10,10] 上固定数据的拟合。 import paddle import paddle.nn as nn import numpy as np import matplotlib.…

GWAS数据和软件下载

这部分主要是数据获取,以及软件配置方法。 一、配套数据和代码 数据和代码目前在不断的更新,最新的教程可以私信,我通过后手动发送最新版的pdf和数据代码。发送的压缩包,有电子版的pdf和数据下载链接,里面是最新的百度网盘的地址,下载到本地即可。然后根据pdf教程,结合配套的…

win32汇编环境,在对话框中画五边形与六边形

;运行效果 ;win32汇编环境,在对话框中画五边形与六边形 ;展示五边形与六边形的画法 ;将代码复制进radasm软件里,直接编译可运行.重要部分加备注。 ;下面为asm文件 ;>>>>>>>>>>>>>>>>>>>>>>>>>&g…

springcloud 介绍

Spring Cloud是一个基于Spring Boot的微服务架构解决方案集合&#xff0c;它提供了一套完整的工具集&#xff0c;用于快速构建分布式系统。在Spring Cloud的架构中&#xff0c;服务被拆分为一系列小型、自治的微服务&#xff0c;每个服务运行在其独立的进程中&#xff0c;并通过…

如何进行千万级别数据跑批优化

目录 背景问题分析解决方案 数据库问题分片广播分批获取事务控制充分利用服务器资源MQ消费任务并行动态调整并发度失败任务如何继续下游接口时间线程安全异常 & 监控 总结 背景 定义&#xff1a;跑批是指在特定日期对大量数据进行定时处理的过程。在金融领域&#xff0c;…