首页 > 系统相关 >Linux系统下追加记录到文件中的实例代码解读

Linux系统下追加记录到文件中的实例代码解读

时间:2022-10-20 09:26:00浏览次数:46  
标签:fp RECORD mapped 解读 record 实例 Linux integer sizeof

今日阅读Linux程序设计第四版,找到一个使用mmap函数的实例

问题描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
该程序主要定义一个结构体,随后利用mmap,msync以及munmap函数对其进行内容追加,定位以及修改内容的操作。

先自己实现该代码,随后进行编译

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <stdlib.h>


typedef struct{
    int integer;
    char string[24];
} RECORD;

#define NRECORDS (100)


int main()
{
    RECORD record, *mapped;
    int i, f;
    FILE *fp;

    fp = fopen("records.dat","w+");
    for(i = 0 ; i < NRECORDS; i++)
    {

        record.integer = i;
        sprintf(record.string,"RECORD-%d",i);
        fwrite(&record,sizeof(record),1,fp);

    }
    fclose(fp);

    fp = fopen("records.dat","r+");
    fseek(fp,43*sizeof(record),SEEK_SET);
    fread(&record,sizeof(record),1,fp);

    record.integer = 143;
    sprintf(record.string,"RECORD-%d",record.integer);

    fseek(fp,43*sizeof(record),SEEK_SET);
    fwrite(&record,sizeof(record),1,fp);
    fclose(fp);


    f = open("records.dat",O_RDWR);
    mapped = (RECORD *)mmap(0,NRECORDS*sizeof(record),PROT_READ|PROT_WRITE,MAP_SHARED,f,0);

    mapped[43].integer = 243;
    sprintf(mapped[43].string,"RECORD-%d",mapped[43].integer);

    msync((void *)mapped, NRECORDS*sizeof(record),MS_ASYNC);
    munmap((void *)mapped,NRECORDS*sizeof(record));
    close(f);

    exit(0);
}

随后逐行进行解读

	RECORD record, *mapped;
    int i, f;
    FILE *fp;

    fp = fopen("records.dat","w+");
    for(i = 0 ; i < NRECORDS; i++)
    {

        record.integer = i;
        sprintf(record.string,"RECORD-%d",i);
        fwrite(&record,sizeof(record),1,fp);

    }

先fopen创建一个records.dat文件,随后for循环100次,每次record结构体内integer整形值+1,将RECORD结构体record内的integer整形值设定为i
使用sprintf函数,发送格式化输出到record的string字符串中,然后使用fread函数,
fwrite 用于写记录,这里的记录是指一串固定长度的字节,比如一个 int、一个结构体或者一个定长数组。

fwrite(&record,sizeof(record),1,fp);

意思为,从fp流中取得1*sizeof(record)个大小的字节,存放到record结构体当中

    fp = fopen("records.dat","r+");
    fseek(fp,43*sizeof(record),SEEK_SET);
    fread(&record,sizeof(record),1,fp);

    record.integer = 143;
    sprintf(record.string,"RECORD-%d",record.integer);

    fseek(fp,43*sizeof(record),SEEK_SET);
    fwrite(&record,sizeof(record),1,fp);
    fclose(fp);

随后以读的方式打开record.dat文件,

fseek函数专用于重定向流的位置

参数声明

	int fseek(FILE *stream, long int offset, int whence)
  • stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了流。
  • offset -- 这是相对 whence
    的偏移量,以字节为单位。
  • whence -- 这是表示开始添加偏移 offset 的位置。它一般指定为下列常量之一,其中shence的参数可设置为:
    SEEK_SET 文件的开头
    SEEK_CUR 文件指针的当前位置
    SEEK_END 文件的末尾
	fseek(fp,43*sizeof(record),SEEK_SET);

意思为从打开的fp流开头往后第43个record的位置开始操作

	fread(&record,sizeof(record),1,fp);

    record.integer = 143;
    sprintf(record.string,"RECORD-%d",record.integer);

最后将从43号位置开始的record整个读出,放到record变量中,注意,使用指针,此时是从地址读取,因此内存中实际的RECORD【43】也发生了更改,然后将这个位置的string字符数组改为:RECORD-143

    fseek(fp,43*sizeof(record),SEEK_SET);
    fwrite(&record,sizeof(record),1,fp);
    fclose(fp);

将该位置的record重新写回对应内存,关闭这个流

	f = open("records.dat",O_RDWR);
    mapped = (RECORD *)mmap(0,NRECORDS*sizeof(record),PROT_READ|PROT_WRITE,MAP_SHARED,f,0);

    mapped[43].integer = 243;
    sprintf(mapped[43].string,"RECORD-%d",mapped[43].integer);

    msync((void *)mapped, NRECORDS*sizeof(record),MS_ASYNC);
    munmap((void *)mapped,NRECORDS*sizeof(record));

继续打开records.dat文件,采用可读写方式打开
mmap函数用于建立内存映射,并返回映射首地址指针mapped
该步骤将定位到整个RECORD数组的首地址
并修改其中的43号位置的integer

mmap函数详细解释

	void* mmap(void* start,size_t length,int prot,int flags,int fd,off_t offset);
  • 参数start:指向欲映射的内存起始地址,通常设为 NULL,代表让系统自动选定地址,映射成功后返回该地址
  • 参数length:代表将文件中多大的部分映射到内存。
  • 参数prot:映射区域的保护方式。可以为以下几种方式的组合:
    PROT_EXEC 映射区域可被执行
    PROT_READ 映射区域可被读取
    PROT_WRITE 映射区域可被写入
    PROT_NONE 映射区域不能存取
  • 参数flags:影响映射区域的各种特性
  • 参数fd:要映射到内存中的文件描述符。
  • 参数offset:文件映射的偏移量,通常设置为0
	msync((void *)mapped, NRECORDS*sizeof(record),MS_ASYNC);
    munmap((void *)mapped,NRECORDS*sizeof(record));

msync函数用于把从传入起始位置开始的修改写回到内存中
munmap函数可用于释放该内存段,将mapped指针指向的部分释放

Linux程序设计第四版一书中对这一部分解释如下:
在这里插入图片描述
其实此方法与上一步骤当中的内存映射方法达到目的相同
第一种方法通过定位到流的具体位置做出精确修改,第二种方法通过mmap函数将整个RECORD结构体数组的指针找到,通过该指针找到具体位置。因为在C中,数组本身就是一个指针。

标签:fp,RECORD,mapped,解读,record,实例,Linux,integer,sizeof
From: https://www.cnblogs.com/lvtongxuan666/p/16808547.html

相关文章

  • Linux源码编译——添加新模块
    C源码文件(如new_module.c)添加到适当目录在menuconfig中增加新条目:修改C源码文件所在目录下的Kconfig文件,参考该文件中已有的编译选项照猫画虎,添加新的项configNEW_MOD......
  • Linux实战笔记_CentOS 7中格式化磁盘
    fdisk-l#检查是否添加成功(添加一块磁盘并重启计算机后)fdisk/dev/sdb#格式化磁盘mount/dev/sdb1/opt#挂载到/opt目录df-h......
  • Linux实战笔记_ 如何远程访问Kali?
    注:基于2018年安装的kali版本。启动ssh服务/etc/init.d/sshstart或servicesshstart#启动ssh服务/etc/init.d/sshstatus或者servicesshstatus#查看ssh服......
  • ES生成器函数使用实例
    <!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metahttp-equiv="X-UA-Compatible"content="IE=edge"><metaname="viewport"content......
  • 使用linux上传代码到gitee
    (文章目录)一、git的安装sudoyum-yinstallgit检查是否安装成功git--version(这个是输入)gitversion1.8.3.1(若安装成功会自动弹出) 二、过程1.仓库链接......
  • 解读event.returnValue和return false
    前言:首先我们要清楚returnValue是IE的一个属性,如果设置了该属性,它的值比事件句柄的返回值优先级要高,把它的值设置为false,可以取消发生事件源元素的默认动作;returnfalse就......
  • FLTK基于cmake编译以及使用(Windows、macOS以及Linux)
    最近因为一些学习的原因,需要使用一款跨平台的轻量级的GUI+图像绘制C/C++库。经过一番调研以后,最终从GTK+、FLTK中选出了FLTK,跨平台、够轻量。本文将在Windows、macOS两套......
  • Linux 中的硬链接和符号链接
    https://linux265.com/news/7471.html类似Windows系统中的快捷方式,在Linux系统中它们叫链接,存在两种形式,一种是硬链接,一种是符号链接。通常,符号链接也被称为软链接,下......
  • (Linux)不挂断启动进程
    环境:腾讯云Ubuntux86_64问题:在配置应用时,需要让他后台启动,关闭ssh连接也要可以保持后台运行解决办法:1、使用nohup参考链接:https://zhuanlan.zhihu.com/p/344554760no......
  • 宋宝华: 关于Linux进程优先级数字混乱的彻底澄清
    找了好久终于找到你了,这是网上关于优先级描述最清晰的一个帖子。没有之一。必须转发。                所以从上面的描述来说,先是区分调......