内存映射文件

sat*_*sat 2 c unix mmap memory-mapped-files

我编写了一个代码,用于将内容写入映射缓冲区,该缓冲区使用mmap()系统调用进行映射.在我对映射缓冲区进行了一些更改之后,我调用了msync().它应该更新到磁盘上的文件.

但是,它没有对磁盘上的文件进行任何更改.

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h> 
#include <sys/types.h>
#include <sys/stat.h>
#include<sys/mman.h>
#include<fcntl.h>
#define FILEMODE S_IRWXU | S_IRGRP | S_IROTH
#define MAX 150

main(int argc,char *argv[])
{
int fd,ret,len;
long int len_file;
struct stat st;
char *addr;
char buf[MAX];


if(argc > 1)
{
    if((fd = open(argv[1],O_RDWR | O_APPEND | O_CREAT ,FILEMODE)) < 0)
        perror("Error in file opening");

    if((ret=fstat(fd,&st)) < 0)
        perror("Error in fstat");

    len_file = st.st_size;

           /*len_file having the total length of the file(fd).*/


    if((addr=mmap(NULL,len_file,PROT_READ|PROT_WRITE,MAP_PRIVATE,fd,0)) == MAP_FAILED)
        perror("Error in mmap");

    len = len_file; 

    while((fgets(buf,MAX,stdin)) != NULL)
    {
        strcat(addr+len,buf);
        printf( "Val:%s\n",addr ) ; //Checking purpose
        len = len + (strlen(buf));
    }
    if((msync(addr,len,MS_SYNC)) < 0)
        perror("Error in msync");

    if( munmap(addr,len) == -1)
        printf("Error:\n");
    printf("addr %p\n",addr);
}
else
{
    printf("Usage a.out <filename>\n");
}
}
Run Code Online (Sandbox Code Playgroud)

caf*_*caf 18

如果希望更改反映在磁盘文件中,则必须将文件映射为MAP_SHARED,而不是MAP_PRIVATE.

此外,您无法仅通过在映射结束之后编写来扩展文件.您必须使用ftruncate()将文件扩展为新大小,然后更改映射以包括文件的新部分.更改映射的可移植方法是取消映射映射,然后使用新大小重新创建映射; 在Linux上你可以改用mremap().

lenlen_file变量的类型应该的size_t,你应该使用memcpy(),而不是strcat(),因为你知道该字符串的准确长度,正是要复制它,你希望复制空终止.

您的代码的以下修改适用于Linux(使用mremap()):

#define _GNU_SOURCE
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include<sys/mman.h>
#include<fcntl.h>
#define FILEMODE S_IRWXU | S_IRGRP | S_IROTH
#define MAX 150

int main(int argc,char *argv[])
{
    int fd, ret;
    size_t len_file, len;
    struct stat st;
    char *addr;
    char buf[MAX];

    if (argc < 2)
    {
        printf("Usage a.out <filename>\n");
        return EXIT_FAILURE;
    }

    if ((fd = open(argv[1],O_RDWR | O_CREAT, FILEMODE)) < 0)
    {
        perror("Error in file opening");
        return EXIT_FAILURE;
    }

    if ((ret = fstat(fd,&st)) < 0)
    {
        perror("Error in fstat");
        return EXIT_FAILURE;
    }

    len_file = st.st_size;

    /*len_file having the total length of the file(fd).*/

    if ((addr = mmap(NULL,len_file,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0)) == MAP_FAILED)
    {
        perror("Error in mmap");
        return EXIT_FAILURE;
    }

    while ((fgets(buf,MAX,stdin)) != NULL)
    {
        len = len_file;
        len_file += strlen(buf);
        if (ftruncate(fd, len_file) != 0)
        {
            perror("Error extending file");
            return EXIT_FAILURE;
        }
        if ((addr = mremap(addr, len, len_file, MREMAP_MAYMOVE)) == MAP_FAILED)
        {
            perror("Error extending mapping");
            return EXIT_FAILURE;
        }
        memcpy(addr+len, buf, len_file - len);
        printf( "Val:%s\n",addr ) ; //Checking purpose
    }
    if((msync(addr,len,MS_SYNC)) < 0)
        perror("Error in msync");

    if (munmap(addr,len) == -1)
        perror("Error in munmap");

    if (close(fd))
        perror("Error in close");

    return 0;
}
Run Code Online (Sandbox Code Playgroud)