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

这篇具有很好参考价值的文章主要介绍了文件IO_文件读写(附Linux-5.15.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)正常情况下文件偏移量工作原理

文件IO_文件读写(附Linux-5.15.10内核源码分析),Linux环境编程,linux,物联网,c语言,vim,tcp/ip

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

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

文件IO_文件读写(附Linux-5.15.10内核源码分析),Linux环境编程,linux,物联网,c语言,vim,tcp/ip

 图 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参数解析:

文件IO_文件读写(附Linux-5.15.10内核源码分析),Linux环境编程,linux,物联网,c语言,vim,tcp/ip

图 2-1 lseek参数解析

函数返回值:

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

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

2.2 lseek内核源码分析

文件IO_文件读写(附Linux-5.15.10内核源码分析),Linux环境编程,linux,物联网,c语言,vim,tcp/ip

 图 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内核源码分析

文件IO_文件读写(附Linux-5.15.10内核源码分析),Linux环境编程,linux,物联网,c语言,vim,tcp/ip

 图 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内核源码分析

文件IO_文件读写(附Linux-5.15.10内核源码分析),Linux环境编程,linux,物联网,c语言,vim,tcp/ip

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

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

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

本示例模拟图 1-1和图 1-2 流程文章来源地址https://www.toymoban.com/news/detail-571919.html

#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;
}

到了这里,关于文件IO_文件读写(附Linux-5.15.10内核源码分析)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【嵌入式环境下linux内核及驱动学习笔记-(10-内核内存管理)】

    对于包含MMU(内存管理单元)的处理器而言,linux系统以虚拟内存的方式为每个进程分配最大4GB的内存。这真的4GB的内存空间被分为两个部分–用户空间 与 内核空间。用户空间地地址分布为0~3GB,剩下的3 ~ 4GB 为内核空间。如下图。 用户进程通常只能访问用户空间的虚拟地址

    2024年02月11日
    浏览(40)
  • Linux内核源码分析 1:Linux内核体系架构和学习路线

    好久没有动笔写文章了,这段时间经历了蛮多事情的。这段时间自己写了一两个基于不同指令集的 Linux 内核, x86 和 RISC-V 。期间也去做了一些嵌入式相关的工作,研究了一下 ARM 指令集架构。 虽然今年九月份我就要申请了,具体申请 AI 方向还是机器人、嵌入式、操作系统、

    2024年02月07日
    浏览(42)
  • Linux内核源码分析 (A)常见内核面试题

    系统调用 do_fork() : copy_process() 定时中断 do_timer() 唤醒进程 wake_up_process() :进程由睡眠状态转为 RUNNING 状态 系统调用 sys_sched_yield() 改变进程的调度策略 sched_setscheduler() : 什么情况下会发生调度时机:阻塞操作、中断返回之前(系统调用返回用户空间时)、被唤醒的进程会

    2024年02月10日
    浏览(47)
  • 【Linux 内核源码分析笔记】系统调用

    在Linux内核中,系统调用是用户空间程序与内核之间的接口,它允许用户空间程序请求内核执行特权操作或访问受保护的内核资源。系统调用提供了一种安全可控的方式,使用户程序能够利用内核功能而不直接访问底层硬件。 系统调用: 通过系统调用,用户程序可以请求内核

    2024年02月03日
    浏览(34)
  • 【Linux 内核源码分析】RCU机制

    Linux内核的RCU(Read-Copy-Update)机制是一种用于实现高效读取和并发更新数据结构的同步机制。它在保证读操作不被阻塞的同时,也能够保证数据的一致性。 RCU的核心思想是通过延迟资源释放来实现无锁读取,并且避免了传统锁带来的争用和开销。具体而言,RCU维护了一个“回

    2024年01月15日
    浏览(65)
  • 【Linux 内核源码分析】物理内存组织结构

    多处理器系统两种体系结构: 非一致内存访问(Non-Uniform Memory Access,NUMA):这种体系结构下,内存被划分成多个内存节点,每个节点由不同的处理器访问。访问一个内存节点所需的时间取决于处理器和内存节点之间的距离,因此处理器与内存节点之间的距离会影响内存访问

    2024年02月22日
    浏览(46)
  • 《Linux内核源码分析》(2)进程原理及系统调用

    操作系统的作用 :作为硬件的使用层,提供使用硬件资源的能力, 进程的作用 :作为操作系统使用层,提供使用操作系统抽象出的资源层的能力 进程、线程和程序的区别 :进程指计算机中已运行的程序。进程本身不是基本的运行单位,而是线程的容器。 程序本身只是指令

    2024年02月07日
    浏览(40)
  • 【Linux 内核源码分析】进程调度 -CFS 调度器

    Linux内核调度器是负责决定哪个进程在何时执行的组件。它管理着CPU资源的分配和任务的调度,以确保系统资源的合理利用和任务的高效执行。Linux内核中常见的调度器有多种,包括经典的O(1)调度器、CFS(Completely Fair Scheduler)调度器等。这些调度器根据不同的策略和算法来进

    2024年01月17日
    浏览(46)
  • 【Linux 内核源码分析】内存管理——Slab 分配器

    在Linux内核中,伙伴分配器是一种内存管理方式,以页为单位进行内存的管理和分配。但是在内核中,经常会面临结构体内存分配问题,而这些结构体的大小通常是小于一页的。如果使用伙伴分配器来分配这些小内存,将造成很大的内存浪费。因此,为了解决这个问题,Sun公

    2024年02月22日
    浏览(46)
  • Linux内核源码分析 (B.2)虚拟地址空间布局架构

    Linux内核只是操作系统当中的一部分,对下管理系统所有硬件设备,对上通过系统调用向 Library Routine 或其他应用程序提供API接口。 内存管理可以通过以下三个维度进行介绍: 用户空间 相当于应用程序使用 malloc() 申请内存,通过 free() 释放内存。 malloc() / free() 是 glibc 库的内

    2024年02月09日
    浏览(52)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包