利用mmap和数组方式的存取操作对结构化数据文件进行修改

本文通过一个具体的C语言程序示例,介绍了如何使用mmap进行内存映射文件操作,包括文件的读写、修改及同步回写到磁盘的过程。同时探讨了在使用mmap过程中可能遇到的段错误等问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 1 #include <unistd.h>
 2 #include <stdio.h>
 3 #include <sys/mman.h>
 4 #include <fcntl.h>
 5 #include <stdlib.h>
 6 
 7 typedef struct//定义了一个包含下面两个数据类型的结构体
 8 {
 9     int integer;
10     char string[24];
11 } RECORD;//别名为RECORD
12 
13 #define NRECORDS (100)//宏定义NRECORDS为(100)
14 
15 int main()//主函数
16 {
17     RECORD record, * mapped;//分别实现了一个record结构体,和一个指向结构体的指针mapped
18     int i,f;
19     FILE * fp;//定义了流指针fp
20     
21     fp=fopen("records.dat","w+");//以修改的方式打开文件,并将文件长度截断为0,没有的话就创建
22     for (i=0;i<NRECORDS; i++)//进入一个条件循环,循环100次
23     {
24         record.integer=i;//给结构体的证书部分赋值为i
25         sprintf(record.string, "RECORD-%d",i);//把格式化的输出传送到指定的地方,-代表左对齐
26         fwrite(&record, sizeof(record), 1, fp);//把赋值完成的record写入fp中,写入一个指定长度
27     }
28     fclose(fp);//关闭打开的流指针
29     
30     
31     
32     fp=fopen("records.dat","r+");//以写的方式打开文件,并创建文件流fd
33     fseek(fp,43*sizeof(record),SEEK_SET);//设置文件流的下一次读写的位置,最后一个参数表示绝对位置
34     fread(&record,sizeof(record), 1, fp);//从fd中读取一个指定长度,到record结构体中
35     
36     record.integer=143;            //设置结构体中第一个元素的值为143
37     sprintf(record.string,"RECORD-%d",record.integer);//同样的把这个值按照左对齐方式传递给结构体的第二个元素
38     
39     fseek(fp,43*sizeof(record),SEEK_SET);//重新设置文件流的下一次读写的位置
40     fwrite(&record,sizeof(record),1,fp);//给文件流写入一个指定长度的record内容
41     fclose(fp);//关闭打开的文件流
42     
43     
44     
45     f=open("record.dat",O_RDWR);//使用系统调用open,以读写的方式打开文件,返回文件描述符f
46     mapped=(RECORD *)mmap(0,NRECORDS*sizeof(record),PROT_READ|PROT_WRITE,MAP_SHARED,f,0);
47     //创建指向0的内存,长度是100个指定长度,权限是读写内存段,flag取MAP_SHARED表示对内存段的修改保存到
48     //磁盘文件中,f就是和内存相关的描述符,偏移是0。总体来说是把文件转化为内存中的结构数组
49     mapped[43].integer=243;//设置结构数组中的第43个元素的第一个值
50     sprintf(mapped[43].string,"RECORD-%d",mapped[43].integer);//同样按照左对齐方式传递给结构数组第二个元素
51     
52     msync((void *)mapped, NRECORDS*sizeof(record),MS_ASYNC);//把内存中的整段的修改按照异步写的方式写回到被映射的文件中
53     munmap((void *)mapped, NRECORDS*sizeof(record));//全部释放这个内存段
54     close(f);//关闭打开的文件描述符
55     
56     exit(0);
57 }

如果是前面不使用mmap程序可以顺利执行,但是加上后面的代码时候,terminal会提示说:

段错误 (核心已转储)

参考文献:

Linux程序设计 Neil Matthew

转载于:https://www.cnblogs.com/kongchung/p/4602024.html

下面是一个简单的 Linux C 语言程序,用于在内存中映射一个文件,然后通过数组方式修改 map 类型的数据文件: ```c #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <sys/mman.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <stdbool.h> #include <stdint.h> #include <map> #define FILE_SIZE 1024 typedef struct { int id; char name[20]; } Person; int main() { int fd; Person *p_map; std::map<int, Person> *person_map; if ((fd = open("file", O_RDWR | O_CREAT | O_TRUNC, 0666)) < 0) { perror("open error"); exit(1); } lseek(fd, FILE_SIZE - 1, SEEK_SET); write(fd, "", 1); if ((p_map = (Person *) mmap(NULL, FILE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) { perror("mmap error"); exit(1); } person_map = new(std::nothrow) std::map<int, Person>; // 将映射区域中的数据读入 map 中 for (int i = 0; i < FILE_SIZE / sizeof(Person); i++) { if (p_map[i].id > 0) { (*person_map)[p_map[i].id] = p_map[i]; } } // 在 map 中插入新的数据 Person new_person = {1001, "Alice"}; (*person_map)[new_person.id] = new_person; // 将 map 中的数据写回到映射区域 int i = 0; for (auto it = person_map->begin(); it != person_map->end(); it++) { memcpy(&p_map[i++], &(it->second), sizeof(Person)); } munmap(p_map, FILE_SIZE); close(fd); // 通过数组方式修改 map 类型的数据文件 if ((fd = open("file", O_RDWR)) < 0) { perror("open error"); exit(1); } Person persons[FILE_SIZE / sizeof(Person)]; memset(persons, 0, FILE_SIZE); if (read(fd, persons, FILE_SIZE) < 0) { perror("read error"); exit(1); } for (int i = 0; i < FILE_SIZE / sizeof(Person); i++) { if (persons[i].id == 1001) { strcpy(persons[i].name, "Bob"); break; } } if (lseek(fd, 0, SEEK_SET) < 0) { perror("lseek error"); exit(1); } if (write(fd, persons, FILE_SIZE) < 0) { perror("write error"); exit(1); } close(fd); return 0; } ``` 上面的代码中,我们首先创建了一个文件,然后使用 mmap 函数将该文件映射到内存中。接着,我们使用 C++ STL 中的 map 类型来存储数据,这个 map 类型的 key 是 int 类型,value 是 Person 类型的结构体。我们从映射的内存区域中读取数据,将其存储到 map 中,然后在 map 中插入新的数据,并将 map 中的数据写回到映射区域。最后,我们释放映射的内存区域,并关闭文件。 接着,我们通过数组方式打开文件,读取数据到内存中,找到对应的数据进行修改,然后将修改后的数据写回到文件中。注意,这里我们使用了 lseek 函数将文件指针移到文件开头,然后使用 write 函数将数据写回到文件中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值