mmap()和fmemopen()的使用

今天Mayuyu遇到了两个比较有意思的函数,即mmap()fmemeopen()函数。

先来看看mmap()函数,本函数的头文件为#include <unistd.h>#include <sys/mman.h>。函数原型如下

返回值:若映射成功则返回映射区的内存起始地址,否则返回MAP_FAILED(-1),错误原因存于errno 中。

错误代码:

  • EBADF  参数fd 不是有效的文件描述词。
  • EACCES  存取权限有误。如果是MAP_PRIVATE 情况下文件必须可读,使用MAP_SHARED 则要有PROT_WRITE 以及该文件要能写入。
  • EINVAL  参数start、length 或offset 有一个不合法。
  • EAGAIN  文件被锁住,或是有太多内存被锁住。
  • ENOMEM  内存不足。

mmap()是用来将某个文件内容映射到内存中,对该内存区域的取值即是直接对该文件内容的读写。在内存中建立页表项,但mmap()调用并没有立即在页表中建立页表项,只有使用到某个地址空间时才会给此页面分配空间。由于涉及到页面置换,需要有一定的物理内存做支撑,如果内存太小,那么刚置换入内存中的页面又被置换出到磁盘上,mmap的性能大大降低。

mmap()的存在主要是为用户程序随机访问大文件提供了一个方便的操作方法。同时为不同进程共享大批量数据提供高效的手段。对特大文件的处理提供了一种有效的方法。

示例:

#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>

int main(int argc, char **argv)
{
	struct stat st;

	//打开文件
	int fd = -1;
	if((fd = open("File", O_RDONLY)) == -1)
	{
		printf("open File error!\n");
		return -1;
	}

    //根据文件描述符取出文件状态
	if(fstat(fd, &st) == -1)
	{
		printf("get st error!\n");
		return -1;
	}

    //进行映射
	void *start = NULL;
	if((start = mmap(start, st.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0)) == MAP_FAILED)
	{
		printf("mmap error!\n");
		return -1;
	}

	printf("%s\n", (char *)start);

    //解除映射关系
	if(munmap(start, st.st_size) == -1)
	{
		printf("munmap error!\n");
		return -1;
	}
	close(fd);

	return 0;
}

上面有一个函数为fstat(fd, st),成功返回0,失败返回-1。它是根据文件描述符fd获取文件状态st的,而st是一个结构体,记录了文件的很多状态信息,这个结构体定义如下

其实还有一个函数的作用跟fstat()差不多,即stat()。不同的是stat()的第一个参数表示的是文件名,而不是文件描述符。

mmap()系统调用并不是完全为了共享内存而设计的,它本身提供了一种不同于普通文件的访问方式,进程可以像读取内存那样对普通文件进行操作,当然mmap()是共享内存最主要应用之一。

还有几个与mmap()系统调用有关的函数如下

(1)munmap()函数

函数原型为 :

该调用在进程地址空间解除一个映射关系,addr是调用mmap()返回的地址,len是映射区的大小,当解除映

射关系后,对原来映射地址的访问将会导致段错误。此函数解除成功返回0,否则返回-1

(2)msync()函数

函数原型为 :

一般说来,进程在映射空间的对共享内容的改变并不直接写回到磁盘文件中,往往在调用munmap()后才执

行该操作。可以通过调用msync()实现磁盘上文件内容与共享内存区的内容一致。

  addr: 文件映射到进程空间的地址

    len:  映射空间的大小

    flags:刷新的参数设置,可以取值MS_ASYNC/ MS_SYNC/ MS_INVALIDATE

其中:

取值为MS_ASYNC(异步)时,调用会立即返回,不等到更新的完成;

取值为MS_SYNC(同步)时,调用会等到更新完成之后返回;

取MS_INVALIDATE(通知使用该共享区域的进程,数据已经改变)时,在共享内容更改之后,使得文件的其

他映射失效,从而使得共享该文件的其他进程去重新获取最新值

此函数成功则返回0,失败则返回-1

(3)madvise()函数

在调用mmap()时内核只是建立了逻辑地址到物理地址的映射表,并没有映射任何数据到内存。 在你要访问数

据时内核会检查数据所在分页是否在内存,如果不在,则发出一次缺页中断,linux默认分页为4K,可以想象

读一个将近2G的电影文件要发生多少次中断。解决办法如下

madvise()mmap()搭配起来使用,在使用数据前告诉内核这一段数据我要用,将其一次读入内存,避免

中断。madvise()这个函数可以对映射的内存提出使用建议,从而提高内存,大大改善性能。

函数原型 :

参数说明: addr  为mmap()调用获得的映射地址空间首地址。

len   为映射空间的大小。

behav 关于这个参数,详情请点这里。

执行成功返回0,否则返回-1。使用方法如下

代码:

<strong><span style="font-size:18px;">#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>

int main(int argc, char **argv)
{
	struct stat st;

	//打开文件
	int fd = -1;
	if((fd = open("File", O_RDONLY)) == -1)
	{
		printf("open File error!\n");
		return -1;
	}

    //根据文件描述符取出文件状态
	if(fstat(fd, &st) == -1)
	{
		printf("get st error!\n");
		return -1;
	}

    //进行映射
	void *start = NULL;
	if((start = mmap(start, st.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0)) == MAP_FAILED)
	{
		printf("mmap error!\n");
		return -1;
	}

	//使用advise()调用
	if(madvise(start, st.st_size, MADV_WILLNEED | MADV_SEQUENTIAL) == -1)
	{
		printf("madvise error!\n");
		return -1;
	}

	printf("%s\n", (char *)start);

    //解除映射关系
	if(munmap(start, st.st_size) == -1)
	{
		printf("munmap error!\n");
		return -1;
	}
	close(fd);

	return 0;
}
</span></strong>

关于mmap()调用Mayuyu已经介绍了很多了,接下来介绍另一个系统调用,即fmemopen()

mmap()调用是将文件映射到内存中,也就是说通过mmap()调用可以把文件当内存使用。而fmemopen()调用正好相反,通过fmemopen()调用可以把内存当文件使用。接下来将会详细介绍fmemopen()调用。

头文件:#include <stdio.h>

函数原型 :

参数说明:这个比较明显,就不说了,后面用实例说明即可。

这个应用场合较多,比如有些文件不支持内存操作,但是支持文件操作的。

代码:

#include <string.h>
#include <stdio.h>

static char buff[] = "Mayuyu is from Japan";

int main(int argc, char **argv)
{
    int len = strlen(buff);
	FILE *fd = fmemopen(buff, len, "r");
	if(fd == NULL)
	{
		printf("get file error!\n");
		return -1;
	}

    char ch;
	while((ch = fgetc(fd)) != EOF)
		printf("%c", ch);
	puts("");

	fclose(fd);

	return 0;
}
时间: 2024-11-06 03:31:18

mmap()和fmemopen()的使用的相关文章

linux共享内存之mmap

这应该可以算得上是IPC的一种,虽然效率可能并没有其它IPC方式高. 看到map很容易联想到映射.的确,mmap就是一种映射方式,将打开的文件和一段连续的内存做映射.使得对内存进行操作即可以实现对文件的读写,反过来,也就是说,可以通过这种方式来达到进程通信. mmap系列涉及三个函数. void * mmap(void *buf, size_t len, int prot, int flag, int fd, off_t offset); 此函数建立一个共享内存,prot即为权限,可选值有PRO

mmap 与 read/write

mmap与read/write两条路线对文件的访问比较 我们知道无论是通过mmap或read/write访问文件在内核中都必须经过缓存, 当需要从文件读写内容时,都经过内存拷贝的方式与内核中的缓存进行通讯.     1. 用read/write方式,用户须向内核指定要读多少,内核再把得到的内容从内核缓存拷向用户空间:写也须要有一个大致如此的过程.     2. mmap的作用是通过把文件的某一块内容映射到用户空间上,即将之前所述的内核缓存映射到用户空间,这样就可以直接通过内核缓冲池读写这一块内容

linux中mmap系统调用原理分析与实现

参考文章:http://blog.csdn.net/shaoguangleo/article/details/5822110 linux中mmap系统调用原理分析与实现 1.mmap系统调用(功能)      void* mmap ( void * addr , size_t len , int prot , int flags ,int fd , off_t offset )      内存映射函数mmap, 负责把文件内容映射到进程的虚拟内存空间, 通过对这段内存的读取和修改,来实现对文件的

mmap存储映射IO

mmap,munmap-- #include <sys/mman.h> void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); int munmap(void *addr, size_t length); int mprotect(void *addr, size_t len, int prot); int msync(void *addr, size_t length, int fla

第二十天:mmap内存映射

可以说,一天的时间都在了解内存映射mmap这个函数,冯诺依曼结构中表示运算器不能直接对硬盘上的文件进行操作.mmap函数的功能就是将文件映射到某一段内存中,然后操作内存就相当与操作文件.这样的话对文件操作更加方便.mamp函数的定义如下:void *mmap(void *start,size_t length,int prot,int flags,int fd,off_t offsize);一共有六个参数,参数算是比较多了.第一个表示映射内存的起始地址,如果为NULL,那么操作系统会自动的找到空

linux mmap系统调用

函数原型: void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); 作用:将文件映射到以addr为起始地址的进程内存空间,在调用时,通常将addr参数传为NULL,由内核选择起始的虚拟地址空间 对应的munmap(2)系统调用解除映射关系,将内存中的数据写入到文件.可以这样理解,调用munmap之后,mmap返回的指针为野指针了,不能够再访问其指向的空间 在mmap(2)返回之后,可以通过

MMAP和DIRECT IO区别【转】

转自:http://www.cnblogs.com/zhaoyl/p/5901680.html 看完此文,题目不言自明.转自 http://blog.chinaunix.net/uid-27105712-id-3270102.html 在Linux 开发中,有几个关系到性能的东西,技术人员非常关注:进程,CPU,MEM,网络IO,磁盘IO.本篇文件打算详细全面,深入浅出.剖析文件IO的细节.从多个角度探索如何提高IO性能.本文尽量用通俗易懂的视角去阐述.不copy内核代码. 阐述之前,要先有个大

【转】mmap 与 read/write

本文转自http://www.cnblogs.com/KevinT/p/3823286.html mmap与read/write两条路线对文件的访问比较 我们知道无论是通过mmap或read/write访问文件在内核中都必须经过缓存, 当需要从文件读写内容时,都经过内存拷贝的方式与内核中的缓存进行通讯. 1. 用read/write方式,用户须向内核指定要读多少,内核再把得到的内容从内核缓存拷向用户空间:写也须要有一个大致如此的过程. 2. mmap的作用是通过把文件的某一块内容映射到用户空间上

MMAP和DIRECT IO区别

看完此文,题目不言自明.转自 http://blog.chinaunix.net/uid-27105712-id-3270102.html 在Linux 开发中,有几个关系到性能的东西,技术人员非常关注:进程,CPU,MEM,网络IO,磁盘IO.本篇文件打算详细全面,深入浅出.剖析文件IO的细节.从多个角度探索如何提高IO性能.本文尽量用通俗易懂的视角去阐述.不copy内核代码. 阐述之前,要先有个大视角,让我们站在万米高空,鸟瞰我们的文件IO,它们设计是分层的,分层有2个好处,一是架构清晰,二