如何使用 mmap 映射空文件

How to map an empty file using mmap

我正在尝试创建一个空文件(如果它不存在)。而不是使用 mmap() 映射它,这样我就可以将它传递给我的其他程序进行编写。我不确定 mmap 的哪些参数适合空文件。我的代码适用于非空文件,但如果文件为空

,则会出现错误 "Invalid argument"

代码程序1(如果不存在则只创建一个空文件)

int i;
int fd = open("/home/sungmin/dummy_programs/dummy.txt", O_RDONLY | O_CREAT, 0777);
char *pmap;
pid_t child;

if (fd == -1)
{
    perror("Error opening file for writing");
    exit(EXIT_FAILURE);
}        

struct stat fileInfo = {0};

if (fstat(fd, &fileInfo) == -1)
{
    perror("Error getting the file size");
    exit(EXIT_FAILURE);
}

/*if (fileInfo.st_size == 0)
{
    fprintf(stderr, "Error: File is empty, nothing to do\n");
    exit(EXIT_FAILURE);
}*/

pmap = mmap(0, fileInfo.st_size, PROT_READ | PROT_EXEC  , MAP_ANONYMOUS, fd, 0);
if (pmap == MAP_FAILED)
{
    close(fd);
    perror("Error mmapping the file");
    exit(EXIT_FAILURE);
}

/* Calling fork function */
if((child=fork())==0){

printf("Iam Child process\n\n");
static char *argv[]={"This is some sample text. I need to write this text in my dummy file.","/home/sungmin/dummy_programs/dummy.txt",NULL};
execv("/home/sungmin/dummy_programs/pro2",argv);
    exit(127); 
}
else { 
    printf("Iam parent, waiting for child process to exit\n\n");        
    waitpid(child,0,0); 
    printf("Existing parent\n\n");
}

/* Don't forget to free the mmapped memory*/
if (munmap(pmap, fileInfo.st_size) == -1)
{
    close(fd);
    perror("Error un-mmapping the file");
    exit(EXIT_FAILURE);
}

/* Un-mmaping doesn't close the file, so we still need to do that.*/
close(fd);

代码 program2(打开与 program1 相同的文件并写入 program1 传递的文本)

 size_t i;
int fd;
char *pmap;
pid_t child;
struct stat fileInfo = {0};
const char *text = argv[0];

fd = open(argv[1], O_RDWR | O_CREAT | O_TRUNC, (mode_t)0600);

if (fd == -1)
{
    perror("Error opening file for writing");
    exit(EXIT_FAILURE);
}  

size_t textsize = strlen(text) + 1; // + [=11=] null character

if (lseek(fd, textsize-1, SEEK_SET) == -1)
{
    close(fd);
    perror("Error calling lseek() to 'stretch' the file");
    exit(EXIT_FAILURE);
}

if (write(fd, "", 1) == -1)
{
    close(fd);
    perror("Error writing last byte of the file");
    exit(EXIT_FAILURE);
}

pmap = mmap(0, textsize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

if (pmap == MAP_FAILED)
{
    close(fd);
    perror("Error mmapping the file");
    exit(EXIT_FAILURE);
}

/* Writting users text to file */
for (i = 0; i < textsize; i++)
{
    pmap[i] = text[i];  
}   

// Write it now to disk
if (msync(pmap, textsize, MS_SYNC) == -1)
{
    perror("Could not sync the file to disk");
}

/* Don't forget to free the mmapped memory*/
if (munmap(pmap, textsize) == -1)
{
    close(fd);
    perror("Error un-mmapping the file");
    exit(EXIT_FAILURE);
}

/* Un-mmaping doesn't close the file, so we still need to do that.*/
close(fd);  

创建文件后需要使用truncate扩展文件长度才能映射。

是的,函数名听起来不对,但truncate实际上可以将文件长度设置为任意数字。请务必使用 4K 的倍数以获得最佳效果。

然后,如果您想保持映射打开以查看程序 1 和程序 2 之间的数据,您需要删除匿名并在程序 1 中使用 MAP_SHARED 进行映射。未共享的映射不会显示其他程序所做的更改。或者它可能,如果它必须从磁盘重新加载。这很奇怪,不要混合共享和非共享映射。

将程序 1 更改为使用 truncate 后,将 lseekwrite 代码从程序 2 中取出。该文件已由程序创建和扩展1.