Read the fourth edition of Linux programming today and find an example of using the mmap function
Problem Description
The program mainly defines a structure, and then uses mmap, msync and munmap functions to append, locate and modify its content.
Implement the code yourself first, then compile it
#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); }
Then read line by line
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); }
First create a records.dat file with fopen, then for loop 100 times, each time the integer integer value in the record structure is +1, and the integer integer value in the RECORD structure record is set to i
Use the sprintf function to send the formatted output to the string string of the record, and then use the fread function,
fwrite is used to write records, where a record refers to a string of fixed-length bytes, such as an int, a structure, or a fixed-length array.
fwrite(&record,sizeof(record),1,fp);
It means to get 1*sizeof(record) bytes from the fp stream and store them in the record structure
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);
Then open the record.dat file in read mode,
where the fseek function is dedicated to redirecting the stream
parameter declaration
int fseek(FILE *stream, long int offset, int whence)
- stream -- This is a pointer to a FILE object that identifies the stream.
- offset -- this is relative whence
The offset of the , in bytes. - whence − This is the position at which to start adding the offset offset. It is generally specified as one of the following constants, where the parameter of shence can be set to:
the beginning of the SEEK_SET file
SEEK_CUR The current position of the file pointer
SEEK_END end of file
fseek(fp,43*sizeof(record),SEEK_SET);
It means to start the operation from the 43rd record position from the beginning of the open fp stream
fread(&record,sizeof(record),1,fp); record.integer = 143; sprintf(record.string,"RECORD-%d",record.integer);
Finally, the entire record starting from position 43 will be read out and put into the record variable. Note that when using a pointer, it is read from the address at this time, so the actual RECORD [43] in the memory has also changed, and then this position The string char array was changed to: RECORD-143
fseek(fp,43*sizeof(record),SEEK_SET); fwrite(&record,sizeof(record),1,fp); fclose(fp);
Rewrite the record at this location back to the corresponding memory and close the stream
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));
Continue to open the records.dat file and open it in readable and writable mode
The mmap function is used to create a memory map and return the mapped first address pointer mapped
This step will locate the first address of the entire RECORD array
And modify the integer at position 43
Detailed explanation of mmap function
void* mmap(void* start,size_t length,int prot,int flags,int fd,off_t offset);
- Parameter start: point to the starting address of the memory to be mapped, usually set to NULL, which means let the system automatically select the address, and return the address after the mapping is successful
- Parameter length: represents how much part of the file is mapped to memory.
- Parameter prot: the protection mode of the mapping area. It can be a combination of the following ways:
PROT_EXEC mapped area can be executed
PROT_READ mapped area can be read
PROT_WRITE mapped area can be written
PROT_NONE mapped area cannot be accessed - Parameter flags: various characteristics that affect the mapped area
- Parameters fd: The file descriptor to be mapped into memory.
- Parameter offset: the offset of the file mapping, usually set to 0
msync((void *)mapped, NRECORDS*sizeof(record),MS_ASYNC); munmap((void *)mapped,NRECORDS*sizeof(record));
The msync function is used to write the modifications from the incoming starting position back to memory
The munmap function can be used to free the memory segment, freeing the part pointed to by the mapped pointer
This part is explained in the book Linux Programming Fourth Edition as follows:
In fact, this method achieves the same purpose as the memory mapping method in the previous step
The first method makes precise modifications by locating the specific position of the stream, and the second method finds the pointer of the entire RECORD structure array through the mmap function, and finds the specific position through the pointer. Because in C, the array itself is a pointer.