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

Linux系统下追加记录到文件中


今日阅读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中,数组本身就是一个指针。

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值