文件IO_文件读写(附Linux-5.15.10内核源码分析)

news2024/11/25 18:36:10

目录

1.什么是文件偏移量?

1.1 文件偏移量介绍

1.2 文件偏移量重点

1.3 文件偏移量工作原理

2.文件偏移量设置

2.1 lseek函数

2.2 lseek内核源码分析

3.写文件

3.1 write函数

3.2 write内核源码分析

4.读文件

4.1 read函数

4.2 read内核源码分析

5.文件读写,文件偏移量设置示例代码


1.什么是文件偏移量?

1.1 文件偏移量介绍

在介绍文件偏移量之前,先来喊一个口号:只有真正理解了文件偏移量,你才会懂得文件读写。

文件偏移量是指文件中当前读取或写入位置的指示器。

在Linux中,每个打开的文件都有一个文件偏移量,用于记录下一次读取或写入操作将在文件中发生的位置。文件偏移量是一个以字节为单位的整数值,从文件开头开始计算。

当执行读取或写入操作时,文件偏移量会随之改变。

  • 读取操作会从文件偏移量所指示的位置开始读取数据,并将文件偏移量向后移动到读取操作结束后的位置。
  • 写入操作则会从文件偏移量所指示的位置开始写入数据,并将文件偏移量向后移动到写入操作结束后的位置。
  • 通过改变文件偏移量,可以在文件中定位到特定的位置进行读取或写入操作。

1.2 文件偏移量重点

关于文件偏移量我们需要注意以下几点,只有充分掌握了以下几点才能进行正确的文件读写:

  • 1.文件偏移量对应的是struct file对象的f_pos成员,这个成员由write,read,lseek函数共享,也就是说三个函数都会改变f_pos值。
  • 2.open函数如果设置O_APPEND标识,会改变write函数使用f_pos的行为,具体可以参考write内核源码分析。

1.3 文件偏移量工作原理

(1)正常情况下文件偏移量工作原理

 图 1-1 正常情况下文件偏移量工作原理

(2)设置O_APPEND情况下文件偏移工作原理

 图 1-2 设置O_APPEND情况下文件偏移工作原理

2.文件偏移量设置

2.1 lseek函数

#include <sys/types.h>
#include <unistd.h>

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

函数简介:lseek函数是Linux系统中的一个文件操作函数,用于改变文件读写指针的位置。它可以在文件中任意移动读写指针,实现对文件的随机访问。

函数参数:

fd:文件描述符,指定要进行操作的文件。

offset:偏移量,指定要移动的字节数。正值表示向文件末尾方向移动,负值表示向文件起始位置方向移动。

whence:起始位置,指定了偏移量的参考位置。它可以取以下三个值:

  • SEEK_SET:从文件起始位置开始计算偏移量。
  • SEEK_CUR:从当前读写指针位置开始计算偏移量。
  • SEEK_END:从文件末尾位置开始计算偏移量。

lseek参数解析:

图 2-1 lseek参数解析

函数返回值:

成功:返回新的读写指针位置。

失败:返回-1,并设置errno。

2.2 lseek内核源码分析

 图 2-2 lseek内核源码分析

lseek内核源码主要流程如图 2-2,lseek函数主要工作为更新struct file对象成员f_ops,Linux一切皆文件,不同的文件类型对应的lseek函数具体实现会不一样。

lseek,write,read调用完主要流程都要执行f.file->f_pos = pos更新f_pos的值。

3.写文件

3.1 write函数

#include <unistd.h>

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

函数简介:用于将数据写入文件描述符或设备。

函数参数:

fd:文件描述符,要写入的文件或设备的标符。通常使用open函数打开文件或设备后返回的文件描述符作为参数。

buf:要写入数据的缓冲区的指针,数据将该缓冲区写入到文件描述符指定的位置。

count:要写入的字节数,即从缓冲区中写入的数据长度。

函数返回值:

成功:返回实际写入的字节数。

失败:返回-1,并设置errno。

3.2 write内核源码分析

 图 3-1 write函数内核源码分析

write函数内核源码主要流程如图 3-1,write函数主要工作为将数据写入文件并更新更新struct file对象成员f_ops,不同的文件类型对应的write函数实现会不一样,需要具体情况具体分析。

write函数有一个重点就是当open函数设置O_APPEND标识后,write每次写数据都是从队尾开始,这个特性的实现是write不会用struct file对象成员f_pos指定的位置开始写文件,而是重新计算pos(设置为文件实际大小),使用pos指定的位置开始写文件,根据内核源码,我们就能很清楚理解O_APPEND标识工作原理。

4.读文件

4.1 read函数

#include <unistd.h>

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

函数简介:用于从文件描述符中读取数据。

函数参数:

fd:文件描述符,要读取的文件或设备的标识符。通常使用open函数打开文件或设备后返回的文件描述符作为参数。

buf:存放读取数据的缓冲区的指针。数据将从文件描述符指定的位置读取到该缓冲区。

count:要读取的字节数,即从文件中读取的数据长度。

函数返回值:

成功:返回实际读取的字节数。

失败:返回-1,并设置errno。

4.2 read内核源码分析

 图 4-1 read函数内核源码分析

read函数内核源码主要流程如图 4-1,read函数主要工作为从文件读取并更新更新struct file对象成员f_ops,不同的文件类型对应的read函数实现会不一样,需要具体情况具体分析。

5.文件读写,文件偏移量设置示例代码

本示例模拟图 1-1和图 1-2 流程

#include <sys/types.h>
#include <sys/stat.h>
#include <stdbool.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

#define TEST_FILE "/tmp/test.txt"
#define BUF_SIZE (256)
#define READ_BUF_SIZE (2048)

void print_pos(int fd) {
    int pos = lseek(fd, 0, SEEK_CUR);
    printf("cur pos:%d\n", pos);
}

int write_len_data(int fd, unsigned char len, char ch) {
    unsigned char sbuf[BUF_SIZE] = {0};
    for (unsigned char i = 0; i < len; i++) {
        sbuf[i] = ch;
    }

    int ret = write(fd, sbuf, len);
    if (ret == -1) {
        perror("write error");
        return -1;
    }
    return 0;
}

int read_len_data(int fd, unsigned int len) {
    if (len > READ_BUF_SIZE) return -1;
    char rbuf[READ_BUF_SIZE] = {0};
    return read(fd, rbuf, len);
}


int fpos_test(bool append) {
    int flags = 0;
    if (append) {
        flags = O_RDWR | O_CREAT | O_TRUNC | O_APPEND;
    } else {
        flags = O_RDWR | O_CREAT | O_TRUNC;
    }
    int fd = open(TEST_FILE, flags, 0777);
    if (fd == -1) {
        perror("open error");
        return -1;
    }

    write_len_data(fd, 100, 'a');
    print_pos(fd);
    lseek(fd, 10, SEEK_SET);
    read_len_data(fd, 40);
    print_pos(fd);
    write_len_data(fd, 20, 'b');
    print_pos(fd);

    close(fd);
    return 0;
}

int main(int argc, char *argv[]) {
    fpos_test(false);
    return 0;
}

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

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

相关文章

物流难统计、难管理?学会这招,问题迎刃而解

在当今数字化的时代&#xff0c;商家面临着诸多物流挑战。物流数据人工统计成本高、管理难、决策难是很常见的问题。本文将探讨如何通过智能数据分析解决这些问题&#xff0c;帮助商家提升物流效率和管理能力。 物流数据人工统计&#xff0c;难决策 物流数据沉淀全靠人工线下…

Vue3_简介、CompositionVPI、新的组件

文章目录 Vue3快速上手1.Vue3简介2.Vue3带来了什么1.性能的提升2.源码的升级3.拥抱TypeScript4.新的特性 一、创建Vue3.0工程1.使用 vue-cli 创建2.使用 vite 创建 二、常用 Composition API1.拉开序幕的setup2.ref函数3.reactive函数4.Vue3.0中的响应式原理vue2.x的响应式Vue3…

labview实现呼吸灯颜色渐变效果

呼吸灯效果具有美好的视觉观感&#xff0c;前一段时期感受了一位大佬在MCU中实现呼吸灯颜色渐变效果&#xff0c;很是震撼。这引起了我的兴趣&#xff0c;本文则是实现一种呼吸灯效果(主要在于颜色的渐变体现)。 程序整体视图 程序框图 公式节点程序 int red_is_0 red 0 ?…

探索MR与AIGC技术的发展机遇:教育、医疗领域的前景展望

在当今科技迅猛发展的时代&#xff0c;混合现实&#xff08;MR&#xff09;和增强智能生成创作&#xff08;AIGC&#xff09;技术正逐渐成为教育、医疗领域中的关键驱动力。这两项前沿技术的结合为我们带来了无限的可能性和创新的机遇。 MR技术在教育领域中的发展与机遇是广泛而…

非洲秃鹫优化算法(AVOA)(含MATLAB代码)

先做一个声明&#xff1a;文章是由我的个人公众号中的推送直接复制粘贴而来&#xff0c;因此对智能优化算法感兴趣的朋友&#xff0c;可关注我的个人公众号&#xff1a;启发式算法讨论。我会不定期在公众号里分享不同的智能优化算法&#xff0c;经典的&#xff0c;或者是近几年…

LayUI框架实现OA会议系统——增删改查

目录 前言 1. 配置准备 1.1 Layui框架 1.2 mysql数据库表 1.3 用户管理JSP页面 1.4 新增、修改用户共用界面 2. 后台编写 2.1 编写UserDao类增删改查方法 2.2 R工具类 2.3 BaseDao数据库查询方法 2.4 UserAction控制器类 3. 前台JS编写 3.1 userManage页面JS 3.2…

测试报告?Python自动化测试-Allure测试报告使用大全,一篇全通透

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 安装并配置环境变…

工业相机的基础参数释义

景深&#xff1a; 可以清晰拍摄被测物的距离范围。 工作距离&#xff1a; 相机镜头至被测物的距离。 物像距离&#xff1a; 被测物至芯片靶面的距离。 像元尺寸&#xff1a; 一个像素在长和宽方向上所代表的实际大小&#xff0c;单位通常为微米。像元尺寸越大&#xff0c;分辨率…

记录stm32c8t6使用TIM4_CH1、TIM4_CH2输出PWM波控制编码电机出现的问题

由于之前是使用PB9、PB7引脚即TIM4_ch3\TIM4_ch4&#xff0c;由于项目更改为c8t6的PB、PB7引脚&#xff08;TIM4_ch3\TIM4_ch4&#xff09; 改为配置后发现只有一边的轮子可以转到&#xff0c;明明配置没什么问题&#xff0c;编译也没有报错&#xff0c;最后将pwm的调制模式更改…

Android 进程与进程之间的通信--AIDL详细教程,以传递对象为例,两个app实现

我这里案例是 通过 IPC 传递对象 &#xff08;以DemoBean类为例&#xff09; 如下&#xff1a; AIDL 使用一种简单语法&#xff0c;允许您通过一个或多个方法&#xff08;可接收参数和返回值&#xff09;来声明接口。参数和返回值可为任意类型&#xff0c;甚至是 AIDL 生成的其…

TypeScript 学习笔记 环境安装-类型注解-语法细节-类-接口-泛型

文章目录 TypeScript 学习笔记概述TypeScript 开发环境搭建 类型注解类型推断 数据类型JS的7个原始类型Array数组object、Object 和 {}可选属性 ? 和 可选链运算符?. function函数TS类型: any类型 | unknow类型TS类型: void类型TS类型&#xff1a;never类型 &#xff08;几乎…

数据库应用:CentOS 7离线安装MySQL与Nginx

目录 一、理论 1.安装依赖 二、实验 1.离线安装MySQL与Nginx 2.离线安装Nginx 三、问题 1.执行nginx -v命令报错 四、总结 一、理论 1.安装依赖 &#xff08;1&#xff09;概念 安装依赖是指在软件开发中&#xff0c;为了运行或者编译一个程序或者库&#xff0c;在计…

JVM——类加载和垃圾回收

目录 前言 JVM简介 JVM内存区域划分 JVM的类加载机制 1.加载 双亲委派模型 2.验证 验证选项 3.准备 4.解析 5.初始化 触发类加载 JVM的垃圾回收策略 GC 一&#xff1a;找 谁是垃圾 1.引用计数 2.可达性分析 &#xff08;这个方案是Java采取的方案&#x…

k210学习篇(一)环境搭建

一、为什么选择Canmv开发板? 便宜!便宜!便宜!淘宝200即可买到一个能带摄像头和LCD屏等等的开发板 二、利用Maix Hub在线训练 Maix Hub官网https://maixhub.com/home Maix Hub使用教程:K210学习笔记——MaixHub在线训练模型(新版) 注意: 三、配置开发环境 1.MaixPy IDE…

某网站提交登陆信息加密JS逆向实战分析

1. 写在前面 对于爬虫开发者来说&#xff0c;职业生涯中可能或多或少会遇到各种各样的网站&#xff0c;其中有些必要要求登陆才能浏览。那么模拟登陆的时候发现提交的登陆信息&#xff08;用户名、密码&#xff09;都是经过加密后的&#xff0c;如何处理&#xff1f;这里找到了…

我只改五行代码,接口性能提升了 10 倍!

背景 某公司的一个 ToB 系统&#xff0c;因为客户使用的也不多&#xff0c;没啥并发要求&#xff0c;就一直没有经过压测。这两天来了一个“大客户”&#xff0c;对并发量提出了要求&#xff1a;核心接口与几个重点使用场景单节点吞吐量要满足最低500/s的要求。 当时一想&am…

C++ IO流

文章目录 C语言的输入与输出流是什么?CIO流C标准IO流C文件流 stringstream的简单介绍 C语言的输入与输出 在C语言中,我们使用最频繁的输入输出方式为: scanf 和 printf. scanf : 从输入设备(键盘)读取数据,并将值存放在变量中.printf: 将指定的文字/字符串输出到标准输出设备…

数据库约束与表的关系(数据库系列4)

目录 前言&#xff1a; 1.数据库的约束 1.1约束类型 1.1.1 not null 1.1.2 unique 唯一约束 1.1.3 default 默认值约束 1.1.4 primary key 主键约束 1.1.5 foreign key 外键约束 2.表的关系 2.1 一对一 2.2 一对多 2.3 多对一 3.新增 4.聚合查询 4.1聚合函数 4.…

Pinecone - 向量数据库

文章目录 关于 PineconeRoadMapSemantic SearchChatbots购买查看 API Key创建索引代码调用安装库 pinecone-client查看已经创建的索引创建索引插入数据获取索引统计分析信息查询索引,获取相似向量删除索引关于 Pinecone 官网 : https://www.pinecone.i

利用layui构建OA系统基本操作

一.编写方法&#xff08;增加&#xff0c;删除&#xff0c;修改&#xff0c;查询&#xff09; 通过继承BaseDao来实现通用&#xff0c;从而减少代码量&#xff0c;提高小路 1.增加 public int add(User user) throws Exception {String sql "insert into t_oa_user(name…