C 内存映射文件
我编写了一段代码,用于将内容写入映射的缓冲区,该缓冲区通过使用mmap()系统调用进行映射。 在映射的缓冲区中做了一些更改之后,我调用了msync()。它应该会更新到磁盘上的文件C 内存映射文件,c,unix,mmap,memory-mapped-files,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> #in
#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");
}
}
但是,它没有对磁盘上的文件进行任何更改
#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");
}
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#定义文件模式S|u IRWXU | S|u IRGRP | S|IROTH
#定义最大值150
main(int argc,char*argv[])
{
内部fd、ret、len;
长int len_文件;
结构统计;
char*addr;
char buf[MAX];
如果(argc>1)
{
if((fd=open(argv[1],O|RDWR | O|u APPEND | O|u CREAT,FILEMODE))<0)
perror(“文件打开错误”);
如果((ret=fstat(fd,&st))<0)
perror(“fstat中的错误”);
len_file=st.st_size;
/*具有文件总长度(fd)的len_文件*/
if((addr=mmap(NULL,len_文件,PROT_读取| PROT_写入,MAP_私有,fd,0))==MAP_失败)
perror(“mmap中的错误”);
len=len_文件;
while((fgets(buf,MAX,stdin))!=NULL)
{
strcat(addr+len,buf);
printf(“Val:%s\n”,addr);//检查目的
len=len+(strlen(buf));
}
if((msync(addr,len,MS_SYNC))<0)
perror(“msync中的错误”);
if(munmap(addr,len)=-1)
printf(“错误:\n”);
printf(“地址%p\n”,地址);
}
其他的
{
printf(“用法a.out\n”);
}
}
如果希望更改反映在磁盘文件中,则必须将文件映射为map\u SHARED
,而不是map\u PRIVATE
此外,不能仅通过在映射末尾之外写入来扩展文件。必须使用ftruncate()
将文件扩展到新大小,然后更改映射以包含文件的新部分。更改映射的可移植方法是取消映射,然后使用新大小重新创建映射;在Linux上,您可以使用mremap()
您的len
和len\u文件
变量的类型应该是size\u t
,您应该使用memcpy()
而不是strcat()
,因为您确切地知道字符串的长度,确切地知道要复制它的位置,并且不想复制空终止符
以下代码修改在Linux上工作(使用mremap()
):
定义GNU源
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#定义文件模式S|u IRWXU | S|u IRGRP | S|IROTH
#定义最大值150
int main(int argc,char*argv[])
{
int fd,ret;
文件大小,len;
结构统计;
char*addr;
char buf[MAX];
如果(argc<2)
{
printf(“用法a.out\n”);
返回退出失败;
}
如果((fd=open(argv[1],O|u RDWR | O|u CREAT,FILEMODE))<0)
{
perror(“文件打开错误”);
返回退出失败;
}
如果((ret=fstat(fd,&st))<0)
{
perror(“fstat中的错误”);
返回退出失败;
}
len_file=st.st_size;
/*具有文件总长度(fd)的len_文件*/
if((addr=mmap(NULL,len_文件,PROT_读取| PROT_写入,MAP_共享,fd,0))==MAP_失败)
{
perror(“mmap中的错误”);
返回退出失败;
}
while((fgets(buf,MAX,stdin))!=NULL)
{
len=len_文件;
len_文件+=strlen(buf);
如果(ftruncate(fd,len_文件)!=0)
{
perror(“错误扩展文件”);
返回退出失败;
}
if((addr=mremap(addr,len,len_文件,mremap_可能移动))==MAP_失败)
{
perror(“错误扩展映射”);
返回退出失败;
}
memcpy(addr+len,buf,len_文件-len);
printf(“Val:%s\n”,addr);//检查目的
}
if((msync(addr,len,MS_SYNC))<0)
perror(“msync中的错误”);
if(munmap(addr,len)=-1)
perror(“munmap中的错误”);
如果(关闭(fd))
perror(“关闭错误”);
返回0;
}
请注意,您为文件提供了一个与文件大小完全相同的映射。如果在调用open(2)
时创建该文件,它的长度将为0
,如果内核不从0
长度映射设置任何类型的内存映射,我也不会感到惊讶。(可能是吗?我从来没有试过…)
我建议在执行映射之前使用ftruncate(2)
扩展文件的长度。(请注意,使用ftruncate(2)
扩展文件不是很好移植;并非所有平台都提供扩展功能,也并非所有文件系统驱动程序都支持扩展功能。有关详细信息,请参阅系统手册页。)
您必须使用MAP\u共享的映射才能将文件修改保存到磁盘
你对perror(3)
的使用不太正确perror(3)
不会终止您的程序,因此它将继续执行错误的假设:
if((ret=fstat(fd,&st)) < 0)
perror("Error in fstat");
if((ret=fstat(fd,&st))<0)
perror(“fstat中的错误”);
应改为:
if((ret=fstat(fd,&st)) < 0) {
perror("Error in fstat");
exit(1);
}
if((ret=fstat(fd,&st))<0){
perror(“fstat中的错误”);
出口(1);
}
(或者exit(exit\u FAILURE)
如果你想更具可移植性——我觉得这对眼睛来说有点难,但我生活在Linux世界。)
strcat(3)
希望在dest
字符串的末尾找到一个ASCII NUL字符(字节值0x00
,C表示法'\0'
)——通常的C字符串结尾标记。如果您在这个程序中创建一个ASCII NUL,那么您的文件将不会包含它——毕竟它的长度是零——我不知道通过mmap(2)
读取零字节文件的后果。如果文件已经存在并且包含数据,则文件中可能没有编码ASCII NULstrcat(3)
几乎肯定是写入文件的错误工具。(无论如何,没有人想在他们的文件中使用ASCII NUL。)请尝试使用memcpy(3)
。来自匿名评论