Interpretation of the example code of appending records to files under Linux system

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.

Posted by spidie on Fri, 21 Oct 2022 01:39:30 +1030