内存映射文件使用方法
内存映射原理
内存映射原理
内存映射是一种将磁盘文件映射到内存的操作。
在内存中建立一个虚拟地址空间,该空间与磁盘文件相对应,使得我们可以像访问内存一样访问磁盘文件的内容。
内存映射的原理是通过将磁盘文件的内容映射到内存的一段连续地址空间中。
在内存中指定一个缓冲区,当对这个缓冲区进行读写操作时,实际上是在对磁盘文件进行读写操作。
读取该内存区域的数据时,由于数据已经在内存中,所以读取速度非常快。
内存映射的过程主要包括以下几个步骤:
1. 打开文件:使用文件操作相关的API函数打开需要映射到内存的文件。
2. 创建映射区域:使用内存映射相关的API函数,创建一个映射区域。
将文件的某个区域映射到内存。
3. 访问映射区域:获得映射到内存中的虚拟地址,可以直接对其进行读写操作,就像操作内存一样。
4. 保存修改:如果对映射区域进行了修改,需要使用相关的API函数将修改的内容保存回磁盘文件。
通过内存映射,可以实现大文件的快速读写,提高文件的访问速度。
此外,多个进程可以通过映射同一个文件,实现共享内
存的功能,简化进程间通信的实现。
但需要注意的是,对于大文件的内存映射可能会消耗大量的系统内存,需要进行适当的调优和管理。
内存映射文件
内存映射文件:内存映射文件有三种,第一种是可执行文件的映射,第二种是数据文件的映射,第三种是借助页面交换文件的内存映射.应用程序本身可以使用后两种内存映射.1.可执行文件映射:Windows在执行一个Win32应用程序时使用的是内存映射文件技术.系统先在进程地址空间的0x00400000以上保留一个足够大的虚拟地址空间(0x00400000以下是由系统管理的),然后把应用程序所在的磁盘空间作为虚拟内存提交到这个保留的地址空间中去(我的理解也就是说,虚拟内存是由物理内存和磁盘上的页面文件组成的,现在应用程序所在的磁盘空间就成了虚拟地址的页面文件).做好这些准备后,系统开始执行这个应用程序,由于这个应用程序的代码不在内存中(在页面文件中),所以在执行第一条指令的时候会产生一个页面错误(页面错误也就是说,系统所访问的数据不在内存中),系统分配一块内存把它映射到0x00400000处,把实际的代码或数据读入其中(系统分配一块内存区域,把它要访问的在页面文件中的数据读入到这块内存中,需在注意是系统读入代码或数据是一页一页读入的),然后可以继续执行了.当以后要访问的数据不在内存中时,就可以通过前面的机制访问数据.对于Win32DLL的映射也是同样,不过DLL文件应该是被Win32进程共享的(我想应该被映射到x80000000以后,因为0x80000000-0xBFFFFFFF是被共享的空间).当系统在另一个进程中执行这个应用程序时,系统知道这个程序已经有了一个实例,程序的代码和数据已被读到内存中,所以系统只需把这块内存在映射到新进程的地址空间即可,这样不就实现了在多个进程间共享数据了吗!然而这种共享数据只是针对只读数据,如果进程改写了其中的代码和数据,操作系统就会把修改的数据所在的页面复制一份到改写的进程中(我的理解也就是说共享的数据没有改变,进程改写的数据只是共享数据的一份拷贝,其它进程在需要共享数据时还是共享没有改写的数据),这样就可以避免多个进程之间的相互干扰.2.数据文件的内存映射:数据文件的内存映射原理与可执行文件内存映射原理一样.先把数据文件的一部分映射到虚拟地址空间的0x80000000 - 0xBFFFFFFF,但没有提交实际内存(也就是说作为页面文件),当有指令要存取这段内存时同样会产生页面错误异常.操作系统捕获到这个异常后,分配一页内存,映射内存到发生异常的位置,然后把要访问的数据读入到这块内存,继续执行刚才产生异常的指令(这里我理解的意思是把刚才产生异常的指令在执行一次,这次由于数据已经映射到内存中,指令就可以顺利执行过去),由上面的分析可知,应用程序访问虚拟地址空间时由操作系统管理数据在读入等内容,应用程序本身不需要调用文件的I/O函数(这点我觉得很重要,也就是为什么使用内存映射文件技术对内存的访问就象是对磁盘上的文件访问一样).3.基于页面交换文件的内存映射:内存映射的第三种情况是基于页面交换文件的.一个Win32进程利用内存映射文件可以在进程共享的地址空间保留一块区域(0x8000000 - 0xBFFFFFFF),这块区域与系统的页面交换文件相联系.我们可以用这块区域来存储临时数据,但更常见的做法是利用这块区域与其他进程通信(因为0x80000000以上是系统空间,进程切换只是私有地址空间,系统空间是所有进程共同使用的),这样多进程间就可以实现通信了.事实上Win32多进程间通信都是使用的内存映射文件技术,如PostMessage(),SentMessage()函数,在内部都使用内存映射文件技术.使用内存映射文件的方法:1.利用内存映射文件进行文件I/O操作:CreateFile()-->CreateFileMapping()-->MapViewOfFile()......2.利用内存映射文件实现Win32进程间通信:我只介绍两种常用的方法:第一种方法:两个进程使用同一个文件映射核心对象,打开各自的视图,或者父进程把自己创建的文件映射核心对象继承给子进程使用.这种方法比较安全有效.第二种方法:基于页面交换文件的内存映射对象.在调用CreateFileMapping()函数时,传递的文件句柄为0xFFFFFFFF,系统就从页面交换文件中提交物理内存,然后进程之间按照第一种方法进程通信.这种方法不用事先准备一个特殊的文件(也就是说不用事先调用CreateFile()返回一个文件的句柄),非常方便.。
内存映射文件(专门读写大文件)
内存映射⽂件(专门读写⼤⽂件)引⾔ ⽂件操作是应⽤程序最为基本的功能之⼀,Win32 API和MFC均提供有⽀持⽂件处理的函数和类,常⽤的有Win32 API的CreateFile()、WriteFile()、ReadFile()和MFC提供的CFile类等。
⼀般来说,以上这些函数可以满⾜⼤多数场合的要求,但是对于某些特殊应⽤领域所需要的动辄⼏⼗GB、⼏百GB、乃⾄⼏TB的海量存储,再以通常的⽂件处理⽅法进⾏处理显然是⾏不通的。
⽬前,对于上述这种⼤⽂件的操作⼀般是以内存映射⽂件的⽅式来加以处理的,本⽂下⾯将针对这种Windows核⼼编程技术展开讨论。
内存映射⽂件概述 内存⽂件映射也是Windows的⼀种内存管理⽅法,提供了⼀个统⼀的内存管理特征,使应⽤程序可以通过内存指针对磁盘上的⽂件进⾏访问,其过程就如同对加载了⽂件的内存的访问。
通过⽂件映射这种使磁盘⽂件的全部或部分内容与进程虚拟地址空间的某个区域建⽴映射关联的能⼒,可以直接对被映射的⽂件进⾏访问,⽽不必执⾏⽂件I/O操作也⽆需对⽂件内容进⾏缓冲处理。
内存⽂件映射的这种特性是⾮常适合于⽤来管理⼤尺⼨⽂件的。
在使⽤内存映射⽂件进⾏I/O处理时,系统对数据的传输按页⾯来进⾏。
⾄于内部的所有内存页⾯则是由虚拟内存管理器来负责管理,由其来决定内存页⾯何时被分页到磁盘,哪些页⾯应该被释放以便为其它进程提供空闲空间,以及每个进程可以拥有超出实际分配物理内存之外的多少个页⾯空间等等。
由于虚拟内存管理器是以⼀种统⼀的⽅式来处理所有磁盘I/O的(以页⾯为单位对内存数据进⾏读写),因此这种优化使其有能⼒以⾜够快的速度来处理内存操作。
使⽤内存映射⽂件时所进⾏的任何实际I/O交互都是在内存中进⾏并以标准的内存地址形式来访问。
磁盘的周期性分页也是由操作系统在后台隐蔽实现的,对应⽤程序⽽⾔是完全透明的。
内存映射⽂件的这种特性在进⾏⼤⽂件的磁盘事务操作时将获得很⾼的效益。
快速读取内存文件-内存映射文件的方法
快速读取内存⽂件-内存映射⽂件的⽅法
1、前⾔
Windows提供了3种进⾏内存管理的⽅法:
• 虚拟内存,最适合⽤来管理⼤型对象或结构数组。
• 内存映射⽂件,最适合⽤来管理⼤型数据流(通常来⾃⽂件)以及在单个计算机上运⾏的多个进程之间共享数据。
• 内存堆栈,最适合⽤来管理⼤量的⼩对象。
内存映射⽂件可以⽤于3个不同的⽬的
• 系统使⽤内存映射⽂件,以便加载和执⾏. exe和DLL⽂件。
这可以⼤⼤节省页⽂件空间和应⽤程序启动运⾏所需的时间。
• 可以使⽤内存映射⽂件来访问磁盘上的数据⽂件。
这使你可以不必对⽂件执⾏I/O操作,并且可以不必对⽂件内容进⾏缓存。
• 可以使⽤内存映射⽂件,使同⼀台计算机上运⾏的多个进程能够相互之间共享数据。
Windows确实提供了其他⼀些⽅法,以便在进程之间进⾏数据通信,但是这些⽅法都是使⽤内存映射⽂件来实现的,这使得内存映射⽂件成为单个计算机上的多个进程互相进⾏通信的最有效的⽅法。
参考博客:。
C++中使用内存映射文件处理大文件
C++中使⽤内存映射⽂件处理⼤⽂件引⾔ ⽂件操作是应⽤程序最为基本的功能之⼀,Win32 API和MFC均提供有⽀持⽂件处理的函数和类,常⽤的有Win32 API的CreateFile()、WriteFile()、ReadFile()和MFC提供的CFile类等。
⼀般来说,以上这些函数可以满⾜⼤多数场合的要求,但是对于某些特殊应⽤领域所需要的动辄⼏⼗GB、⼏百GB、乃⾄⼏TB的海量存储,再以通常的⽂件处理⽅法进⾏处理显然是⾏不通的。
⽬前,对于上述这种⼤⽂件的操作⼀般是以内存映射⽂件的⽅式来加以处理的,本⽂下⾯将针对这种Windows核⼼编程技术展开讨论。
内存映射⽂件 内存映射⽂件与虚拟内存有些类似,通过内存映射⽂件可以保留⼀个地址空间的区域,同时将物理存储器提交给此区域,只是内存⽂件映射的物理存储器来⾃⼀个已经存在于磁盘上的⽂件,⽽⾮系统的页⽂件,⽽且在对该⽂件进⾏操作之前必须⾸先对⽂件进⾏映射,就如同将整个⽂件从磁盘加载到内存。
由此可以看出,使⽤内存映射⽂件处理存储于磁盘上的⽂件时,将不必再对⽂件执⾏I/O操作,这意味着在对⽂件进⾏处理时将不必再为⽂件申请并分配缓存,所有的⽂件缓存操作均由系统直接管理,由于取消了将⽂件数据加载到内存、数据从内存到⽂件的回写以及释放内存块等步骤,使得内存映射⽂件在处理⼤数据量的⽂件时能起到相当重要的作⽤。
另外,实际⼯程中的系统往往需要在多个进程之间共享数据,如果数据量⼩,处理⽅法是灵活多变的,如果共享数据容量巨⼤,那么就需要借助于内存映射⽂件来进⾏。
实际上,内存映射⽂件正是解决本地多个进程间数据共享的最有效⽅法。
内存映射⽂件并不是简单的⽂件I/O操作,实际⽤到了Windows的核⼼编程技术--内存管理。
所以,如果想对内存映射⽂件有更深刻的认识,必须对Windows操作系统的内存管理机制有清楚的认识,内存管理的相关知识⾮常复杂,超出了本⽂的讨论范畴,在此就不再赘述,感兴趣的读者可以参阅其他相关书籍。
文件映射 原理
文件映射原理
文件映射是一种计算机存储技术,其原理是将文件系统中的文件与内存中的地址空间进行对应。
通过文件映射,可以使文件在内存中的访问方式与访问普通内存相同,从而简化对文件的读写操作。
具体来说,文件映射通过以下步骤实现:
1. 打开文件:首先,需要使用文件系统提供的接口打开待映射的文件。
这个步骤通常包括指定文件名、路径等信息来定位文件。
2. 创建映射:接下来,需要调用操作系统提供的函数,将文件映射到内存中。
在Windows系统中,可使用CreateFileMapping函数来创建文件映射对象;而在Linux系统中,可以使用mmap函数完成映射。
3. 映射文件到内存:一旦创建了文件映射对象,就可以将其映射到进程的虚拟地址空间中。
文件映射可以将整个文件或者指定的部分映射到内存中,形成映射区域。
4. 内存操作:一旦映射成功,可以将内存中的映射区域当作普通的内存进行读写操作。
对映射区域的读写实际上是对文件的读写操作,映射区域的更新会直接影响到文件的内容。
5. 解除映射:当不再需要使用文件映射时,可以调用相应的函数解除映射。
在Windows系统中,使用CloseHandle函数来关
闭文件映射对象;在Linux系统中,可以使用munmap函数来解除映射。
文件映射的实现原理是利用操作系统的虚拟内存机制。
通过将文件映射到内存中的虚拟地址空间,使得对文件的读写操作可以通过内存地址来完成,而不需要使用文件系统相关的函数。
文件映射的好处是可以提高对文件的读写效率,因为内存访问要比文件访问速度更快。
此外,多个进程可以共享同一个文件的映射,实现数据的共享和通信。
【IT专家】使用.so(共享对象)中的内存映射文件
本文由我司收集整编,推荐下载,如有疑问,请与我司联系使用.so(共享对象)中的内存映射文件使用.so(共享对象)中的内存映射文件[英]Using memory-mapped files from within a .so (shared object) I am getting a segfault when accessing shared memory(memory mapped file, using a fixed address of 0x60000000 ) from within a share object (.so).当从共享对象(.so)中访问共享内存(内存映射文件,使用固定地址0x60000000)时,我得到一个段错误。
We have many applications accessing this shared memory without difficulty. My app is different in that I create a small .so with it and the .so is the one calling mmap and accessing the shared memory.我们有很多应用程序毫无困难地访问此共享内存。
我的应用程序不同之处在于我用它创建一个小的.so 而.so 是调用mmap 并访问共享内存的.so。
The mmap() returns just fine. My requested address is returned back properly. But assoon as I try to access the memory from within this .so, it seg faults.mmap()返回正常。
我要求的地址已正确退回。
但是一旦我尝试从这个.so 中访问内存,就会出现故障。
I can’t figure out what is unique about a .so that would prevent it from accessing sharedmemory this way.我无法弄清楚.so 的独特之处在于它会阻止它以这种方式访问共享内存。
SD卡映射方法
1.进入磁盘管理程序中
同时按住Win + X键,弹出超级菜单。
在弹出的界面选择“磁盘管理”
或同时按住Win + R ,输入“diskmgmt.msc”进入磁盘管理程序中
2.创建SD卡驱动器号和路径
鼠标右击(或长按)SD卡,点击选择“更改驱动器号和路径”
在弹出的对话框中选择“添加”
注:此路径可以是在C盘库文件夹下,也可以在其他的驱动器下
找到您想添加的磁盘目录下,添加一个新的文件夹
以图示所例,我们在新的驱动器D盘中建立了一个“SD”文件夹
添加完成之后,请您点击“确定” 即可。
进入您映射的盘符下,您就可以在您设置的目录下找到您映射的SD卡文件夹。
内存映射文件原理及实例
内存映射文件原理及实例本课中我们将要讲解内存映射文件并且演示如何运用它。
您将会发现使用内存映射文件是非常简单的。
理论:如果您仔细地研究了前一课的例子,就会发现它有一个严重的缺陷:如果您想读的内容大于系统分配的内存块怎么办?如果您想搜索的字符串刚好超过内存块的边界又该如何处理?对于第一个问题,您也许会说,只要不断地读就不解决了吗。
至于第二个问题,您又会说在内存块的边界处做一些特别的处理,譬如放上一些标志位就可以了。
原理上确实是行得通,但是这随问题复杂程度加深而显得非常难以处理。
其中的第二个问题是有名的边界判断问题,程序中许许多多的错误都是由此引起。
想一想,如果我们能够分配一个能够容纳整个文件的大内存块该多好啊,这样这两个问题不都迎刃而解了吗?是的,WIN32的内存映射文件确实允许我们分配一个装得下现实中可能存在的足够大的文件的内存。
利用内存映射文件您可以认为操作系统已经为您把文件全部装入了内存,然后您只要移动文件指针进行读写即可了。
这样您甚至不需要调用那些分配、释放内存块和文件输入/输出的API函数,另外您可以把这用作不同的进程之间共享数据的一种办法。
运用内存映射文件实际上没有涉及实际的文件操作,它更象为每个进程保留一个看得见的内存空间。
至于把内存映射文件当成进程间共享数据的办法来用,则要加倍小心,因为您不得不处理数据的同步问题,否则您的应用程序也许很可能得到过时或错误的数据甚至崩溃。
本课中我们将主要讲述内存映射文件,将不涉及进程间的同步。
WIN32中的内存映射文件应用非常广泛,譬如:即使是系统的核心模块---PE格式文件装载器也用到了内存映射文件,因为PE格式的文件并不是一次性加载到内存中来的,譬如他它在首次加载时只加载必需加载的部分,而其他部分在用到时再加载,这正好可以利用到内存映射文件的长处。
实际中的大多数文件存取都和P E加载器类似,所以您在处理该类问题时也应该充分利用内存映射文件。
内存映射文件本身还是有一些局限性的,譬如一旦您生成了一个内存映射文件,那么您在那个会话期间是不能够改变它的大小的。
内存映射文件的工作原理及使用方法
内存映射文件的工作原理及使用方法内存映射文件(Memory-mapped files)是一种将文件映射到内存的机制,它允许应用程序直接访问磁盘上的文件,而无需进行显式的读写操作。
在内存映射文件中,操作系统将文件的一些区域映射到了进程的虚拟内存空间,从而让应用程序可以像访问内存一样访问文件的内容。
内存映射文件的工作原理及使用方法如下:工作原理:1. 打开文件:应用程序首先使用标准的文件操作函数(如open()打开需要映射的文件。
在打开文件时,操作系统会为该文件维护一个文件描述符(File Descriptor)以及其他相关信息。
2. 创建映射:应用程序使用操作系统提供的内存映射函数(如mmap()将文件的一些区域映射到进程的虚拟内存空间中。
该区域通常以页为单位进行映射,即一个或多个连续的页被映射为一段连续的虚拟内存区域。
3.访问文件:一旦映射创建成功,应用程序就可以像访问内存一样访问文件的内容。
读文件时,应用程序直接读取虚拟内存中的数据,操作系统会自动将数据从磁盘读取到内存中;写文件时,应用程序直接修改虚拟内存中的数据,操作系统也会自动将数据写回磁盘。
4.同步数据:内存映射文件中的数据是与磁盘文件保持同步的。
当应用程序对映射区域进行修改时,操作系统会将数据缓存到内存中,并在适当的时机进行写回磁盘,以保证文件的一致性。
使用方法:1. 准备文件:首先需要准备一个需要映射的文件。
可以通过标准的文件操作函数(如open(、write()创建或修改文件。
2. 打开映射:使用内存映射函数(如mmap()将文件的一些区域映射到虚拟内存中。
需要指定映射的起始位置、映射的长度、映射的权限等参数。
3.访问文件:通过访问虚拟内存中的映射区域,可以读写文件的内容。
可以使用指针操作、数组操作或其他方式来访问映射区域中的数据。
4. 同步数据:在需要时,可以使用内存同步函数(如msync()将内存中修改的数据写回磁盘,以保证文件的一致性。
Python使用mmap实现内存映射文件操作
Python使⽤mmap实现内存映射⽂件操作前⾔内存映射通常可以提⾼I/O的性能,因为使⽤内存映射时,不需要对每个访问都建⽴⼀个单独的系统调⽤,也不需要在缓冲区之间复制数据,内核和⽤户都能很⽅便的直接访问内存。
说明 1)什么叫映射? ==>就是给⼀个对象(可以是变量、物理等),起⼀个唯⼀的别名,建⽴⼀⼀对应的关系; 2)⽂件映射:将磁盘上的⽂件的位置,与进程逻辑地址空间中⼀块⼤⼩相同的区域之间的⼀⼀对应; 3)映射后得到⼀个类似数组类型的东西(mmap.mmap()对象),可以通过类似操作数组的⽅式,达到对⽂件内容更改的⽬的;优点 1)相对于⼆进制⽂件的缺陷 通常读写⽂件时,使⽤read()和write()⽅法,这两种⽅法都是以流的形式进⾏的,也就是⼀个字节接着⼀个字节的读写;如果想从某⼀位置开始读写,使⽤seek()⽅法调整⽂件指针,此⽅法对⼆进制⽂件的操作⾮常不⽅便,因为相对于⼆进制⽂件,数据写⼊⽂件时是以数组的形式,将数据映射到⽂件内,然后就以访问数组的形式访问⽂件,⽽且在对⽂件进⾏修改后,能再次通过此数组将数据同步到⽂件中; 2)某些嵌⼊式设备,寄存器被编址到内存地址空间,我们可以映射/dev/mem某范围,取访问这些寄存器 例如:在树莓派(为学习计算机编程教育设计的⼀种微型电脑)上,有⼀个pwm波形的发⽣器,若想使⽤此发⽣器,就要访问树莓派的寄存器;实际上,寄存器就是物理地址的某⼀特定空间;此时,如果要访问寄存器,需要将 /dev/mem 的某⼀范围,映射到内存中,⽤访问内存的⽅式来访问寄存器; 3)如果多个进程映射同⼀个⽂件,还能实现进程通信的⽬的 多个进程把同⼀个⽂件映射到各⾃的内存空间当中,实际上它们看到的是同⼀个视图,也能实现进程通信的⽬的;本篇,将详细介绍Python内存映射库:mmap。
mmap(读⽂件)使⽤mmap()函数可以创建⼀个内存映射⽂件。
该函数的第1个参数是⼀个⽂件描述符,可以通过file对象的fileno()函数获取;第2个参数是要映射的⽂件部分⼤⼩(单位字节),如果该值为0,映射整个⽂件,如果该参数⼤于⽂件⼤⼩,则扩展该⽂件。
mmap和sendfile使用方法
文章标题:深度探析mmap和sendfile的使用方法一、引言在计算机领域,mmap和sendfile是两种常见的IO操作方式,它们可以有效提高文件的读写效率,降低系统开销。
本文将从浅入深地探讨mmap和sendfile的使用方法,帮助读者更深入地理解这两种技术。
二、mmap的使用方法1. 什么是mmapmmap是一种内存映射文件的技术,它将文件映射到进程的位置区域空间,使得文件可以直接在内存中进行读写操作,而不需要通过系统调用。
2. 使用方法在Linux系统中,使用mmap可以通过以下步骤进行:(1)打开文件:使用open系统调用打开需要映射的文件。
(2)映射文件到内存:使用mmap系统调用将文件映射到进程的位置区域空间。
(3)读写文件:通过访问内存的方式进行文件的读写操作。
(4)解除映射:完成文件读写操作后,使用munmap系统调用将文件从进程的位置区域空间解除映射。
3. 优缺点优点:mmap能够减少系统调用次数,提高文件读写效率,适用于大文件的读写操作。
缺点:当文件较小或需要频繁读写时,mmap的性能可能比较低,且对内存消耗较大。
三、sendfile的使用方法1. 什么是sendfilesendfile是一种零拷贝技术,它可以在内核和用户空间直接进行文件的传输,提高网络IO的效率。
2. 使用方法在Linux系统中,使用sendfile可以通过以下步骤进行:(1)打开文件:使用open系统调用打开需要传输的文件。
(2)传输文件:使用sendfile系统调用将文件内容传输至套接字。
(3)关闭文件:完成文件传输后,使用close系统调用关闭文件描述符。
3. 优缺点优点:sendfile通过内核和用户空间的直接传输,避免了数据在内核空间和用户空间的多次复制,提高了文件传输效率。
缺点:sendfile只能用于文件到套接字的传输,不适用于文件的读写操作,且需要特定的系统支持。
四、个人观点和理解mmap和sendfile是两种不同的IO操作方式,各自适用于不同的场景。
linux 内存映射 mmap用法
linux 内存映射mmap用法一mmap系统调用1.内存映射所谓的内存映射就是把物理内存映射到进程的地址空间之内,这些应用程序就可以直接使用输入输出的地址空间,从而提高读写的效率。
Linux 提供了mmap()函数,用来映射物理内存。
在驱动程序中,应用程序以设备文件为对象,调用mmap()函数,内核进行内存映射的准备工作,生成vm_area_struct结构体,然后调用设备驱动程序中定义的mmap 函数。
2.mmap系统调用mmap将一个文件或者其它对象映射进内存。
文件被映射到多个页上,如果文件的大小不是所有页的大小之和,最后一个页不被使用的空间将会清零。
munmap执行相反的操作,删除特定地址区域的对象映射。
当使用mmap映=映射文件到进程后,就可以直接操作这段虚拟地址进行文件的读写等操作,不必再调用read,write等系统调用.但需注意,直接对该段内存写时不会写入超过当前文件大小的内容采用共享内存通信的一个显而易见的好处是效率高,因为进程可以直接读写内存,而不需要任何数据的拷贝。
对于像管道和消息队列等通信方式,则需要在内核和用户空间进行四次的数据拷贝,而共享内存则只拷贝两次数据:一次从输入文件到共享内存区,另一次从共享内存区到输出文件。
实际上,进程之间在共享内存时,并不总是读写少量数据后就解除映射,有新的通信时,再重新建立共享内存区域。
而是保持共享区域,直到通信完毕为止,这样,数据内容一直保存在共享内存中,并没有写回文件。
共享内存中的内容往往是在解除映射时才写回文件的。
因此,采用共享内存的通信方式效率是非常高的。
基于文件的映射,在mmap和munmap执行过程的任何时刻,被映射文件的st_atime可能被更新。
如果st_atime字段在前述的情况下没有得到更新,首次对映射区的第一个页索引时会更新该字段的值。
用PROT_WRITE 和MAP_SHARED标志建立起来的文件映射,其st_ctime 和st_mtime在对映射区写入之后,但在msync()通过MS_SYNC 和MS_ASYNC两个标志调用之前会被更新。
linux下的内存映射函数mmap详解及示例代码
linux下的内存映射函数mmap详解及示例代码引言概述:在Linux操作系统中,内存映射函数mmap是一种重要的内存管理工具。
它可以将文件或设备映射到进程的地址空间,使得进程可以直接访问这些映射区域的数据。
本文将详细介绍mmap函数的使用方法及示例代码,并从五个方面进行阐述。
正文内容:1. mmap函数的基本介绍1.1 mmap函数的定义和原理1.2 mmap函数的参数和返回值1.3 mmap函数的使用场景和优势2. mmap函数的使用方法2.1 打开文件或设备2.2 调用mmap函数进行内存映射2.3 对映射区域进行读写操作2.4 解除内存映射关系2.5 关闭文件或设备3. mmap函数的常见应用场景3.1 文件的内存映射3.2 共享内存的实现3.3 零拷贝技术的应用3.4 设备的内存映射3.5 动态库的加载和执行4. mmap函数的示例代码4.1 文件的内存映射示例4.2 共享内存的示例4.3 零拷贝技术的示例4.4 设备的内存映射示例4.5 动态库的加载和执行示例5. mmap函数的注意事项和优化技巧5.1 内存对齐的重要性5.2 内存映射的大小和文件大小的关系5.3 内存映射的权限设置5.4 内存映射的性能优化5.5 内存映射的错误处理总结:通过本文的介绍,我们了解了Linux下内存映射函数mmap的详细内容。
我们讨论了mmap函数的基本介绍和使用方法,并给出了常见的应用场景和示例代码。
此外,我们还提到了使用mmap函数时需要注意的事项和优化技巧。
mmap函数在Linux系统中具有重要的作用,熟练掌握它的使用方法对于开发高效、稳定的应用程序非常重要。
mmap的用法
mmap的用法mmap(内存映射)是一种在计算机系统中进行文件与主存之间的映射的技术。
它能够将一个文件或者一个设备映射到主存的一部分,使得应用程序可以像访问内存一样访问文件,提供了一种高效的读取和写入数据的方法。
mmap的用法可以分为三个步骤:打开文件、映射文件、访问数据。
下面我将详细介绍每个步骤的使用方法和注意事项。
1. 打开文件:在使用mmap之前,首先需要通过系统调用打开需要映射的文件。
可以使用open函数来打开文件,如下所示:int fd = open("filename", O_RDWR); 打开文件,并以可读可写的方式打开在打开文件时,需要注意以下几点:- 使用O_RDWR参数可以同时读取和写入文件。
- 文件的访问权限需要注意,通常情况下需要具备可读可写的权限。
- 打开文件后,会返回一个文件描述符fd,后续的操作都需要使用该文件描述符。
2. 映射文件:打开文件后,下一步是将文件映射到主存。
可以使用mmap函数来完成这个操作,如下所示:void *addr = mmap(NULL, length, PROT_READ PROT_WRITE,MAP_SHARED, fd, 0);mmap函数的参数解释如下:- 第一个参数是一个建议的映射地址,通常设置为NULL,让系统自动选择合适的地址。
- 第二个参数是映射的长度,可以通过调用stat或fstat函数来获取文件的大小。
- 第三个参数是映射区域的保护方式,PROT_READ表示可读,PROT_WRITE表示可写。
- 第四个参数是映射区域的共享方式,MAP_SHARED表示与其他所有映射该文件的进程共享内存。
- 第五个参数是文件描述符。
- 第六个参数是文件偏移量,通常设置为0,表示从文件开头开始映射。
在映射文件时,需要注意以下几点:- 映射的地址最好是页对齐的,否则可能会出现性能问题。
- 映射的长度可以通过调用stat或fstat函数来获取文件的大小。
【转载】Windows下内存映射文件的工作原理及使用方法
【转载】Windows下内存映射⽂件的⼯作原理及使⽤⽅法⼀、引⾔ WIN32 API为我们提供了⼀种进⾏⽂件操作的⾼效途径,即内存映射⽂件。
内存映射⽂件允许我们在WIN32进程的虚拟地址空间中保留⼀段内存区域,把⽬标⽂件映射到这段虚拟内存之中。
我们可以⽤存取内存数据的⽅式直接操作⽂件中的数据,就好像这些数据放在内存中⼀样。
⽽实际上,我们并没有、也不需要调⽤API函数来读写⽂件,更不需要⾃⼰提供任何缓冲算法,操作系统将会为我们完成这些⼯作。
使⽤内存映射⽂件能给程序开发⼯作提供极⼤的⽅便,程序的运⾏效率也⾮常⾼。
内存映射⽂件在Windows NT和Windows95中的实现机制略有不同,下⾯主要介绍Windows95下内存映射⽂件的⼯作原理及使⽤⽅法。
⼆、Windows95如何管理WIN32进程的内存空间 内存映射⽂件的实现与Windows95的内存管理有密切的关系,因此先讨论⼀下Windows95在运⾏WIN32进程时的内存管理与划分。
在Windows3.x下,所有Windows应⽤程序共享单⼀的地址空间,任何进程都能够对这⼀空间中属于其他进程的内存进⾏读写操作,甚⾄可以存取操作系统本⾝的重要数据。
在这种环境中,编写不当的应⽤程序或者带有恶意的应⽤程序,就可能破坏其他程序的数据或代码,使得系统运⾏不正常,严重时甚⾄会导致系统崩溃。
在实现了WIN32的操作系统Windows NT和Windows95中,每个WIN32进程拥有⾃⼰的地址空间,⼀个WIN32进程不能存取另⼀个进程地址空间的私有数据,两个进程可以⽤具有相同值的指针寻址,但所读写的只是它们各⾃的数据,这样就⼤⼤减少了进程之间的相互⼲扰,增强了系统的健壮性;另⼀⽅⾯,每个WIN32进程拥有4GB的地址空间,但并不代表它真正拥有4GB的实际物理内存,⽽只是操作系统利⽤CPU的内存分页功能提供的虚拟地址空间。
在⼀般情况下,绝⼤多数虚拟地址并没有物理内存与之对应,在真正可以使⽤这些地址空间之前,还要由操作系统提供实际的物理内存。
内存映射文件MemoryMappedFile使用
内存映射⽂件MemoryMappedFile使⽤所谓内存映射⽂件,其实就是在内存中开辟出⼀块存放数据的专⽤区域,这区域往往与硬盘上特定的⽂件相对应。
进程将这块内存区域映射到⾃⼰的地址空间中,访问它就象是访问普通的内存⼀样。
在.NET中,使⽤MemoryMappedFile对象表⽰⼀个内存映射⽂件,通过它的CreateFromFile()⽅法根据磁盘现有⽂件创建内存映射⽂件,调⽤这⼀⽅法需要提供⼀个与磁盘现有⽂件相对应的FileStream对象。
需要保存的类:[Serializable]public class MyImg{public Image img;public string name;}View CodeMMF定义:public class MMF{private MemoryMappedFile file = null;private MemoryMappedViewStream strem = null;private MemoryMappedViewAccessor acces = null;public MMF(){file = MemoryMappedFile.CreateOrOpen("myMMF", 1024 * 1024, MemoryMappedFileAccess.ReadWrite);strem = file.CreateViewStream();acces = file.CreateViewAccessor();}public void Write(int value){acces.Write(0, value);}public int Read(){int value;acces.Read(0, out value);return value;}public void WriteClass(MyImg img){IFormatter format = new BinaryFormatter();format.Serialize(strem, img);}public MyImg ReadClass(){IFormatter format = new BinaryFormatter();return format.Deserialize(strem) as MyImg;}}View Code界⾯代码:private void button1_Click(object sender, EventArgs e){using (OpenFileDialog dlg = new OpenFileDialog()){dlg.Filter = "*.png|*.png";if (dlg.ShowDialog() == DialogResult.OK){this.pictureBox1.Image = Image.FromFile(dlg.FileName);bel1.Text = Path.GetFileNameWithoutExtension(dlg.FileName);}}}private void button2_Click(object sender, EventArgs e){MyImg img = new MyImg() { img = this.pictureBox1.Image, name = bel1.Text }; myFile.WriteClass(img);}private void button3_Click(object sender, EventArgs e){MyImg img = myFile.ReadClass();this.pictureBox1.Image = img.img;bel1.Text = ;}private void button4_Click(object sender, EventArgs e){label2.Text = myFile.Read().ToString();}private void button5_Click(object sender, EventArgs e){myFile.Write(int.Parse(this.textBox1.Text));}View Code。
内存映射文件的操作
内存映射文件的操作一、概述内存映射文件是将磁盘文件部分或全部映射到物理内存的一块地址空间,通过此地址空间,实现应用程序像访问内存一样便捷地访问磁盘文件。
通常应用程序要访问磁盘文件首先是打开文件,读文件,最后再关闭文件,这是一个非常烦琐的操作过程,尤其是在频繁访问大文件时,应用程序的复杂性和运行效率是无法容忍的,通过使用内存映射文件可以很好的解决这一问题,如图1所示。
图1 内存映射文件二、过程介绍要正确使用内存映射文件必需执行六个过程:一是文件打开或创建;二是创建文件映射;三是将文件数据映射到址址空间;四是解除文件数据映射;五是关闭映射文件;六是关闭文件。
上述过程主要用到四个API函数,下面对上述过程进行详细介绍:文件打开或创建使用CreateFile函数。
调用成功返回一个文件句柄,这个句柄在后面创建映射文件时要用到。
CreatFile函数原型如下:HANDLE CreateFile(LPCTSTR lpFileName, // 文件名DWORD dwDesiredAccess, // 访问模式DWORD dwShareMode, // 共享模式LPSECURITY_ATTRIBUTES lpSecurityAttributes, // 安全属性 DWORD dwCreationDistribution, // 创建方式 DWORD dwFlagsAndAttributes, // 文件属性HANDLE hTemplateFile);参数lpFileName为要打开的文件名,dwDesiredAccess参数描述打开文件访问方式,此参数直接影响内存映射文件的访问方式。
创建文件映射对象CreatFileMapping函数,是为打开的文件指定一块磁盘空间,此空间大小要大于或等于已打开文件大小,否则不能够完整访问文件,即能够将整个文件完整的装入该地址空间内。
CreatFileMapping函数原型如下:HANDLE CreateFileMapping(HANDLE hFile, // 文件句柄LPSECURITY_ATTRIBUTES lpFileMappingAttributes, // 安全属性DWORD flProtect, // 保护属性DWORD dwMaximumSizeHigh, // 映射对象大小高32位DWORD dwMaximumSizeLow, // 映射对象大小低32位LPCTSTR lpName // 文件映射对象名字);参数hFile为已打开或创建的文件句柄;flProtect 参数类似CreateFile 函数中dwDesiredAccess参数,用于指定保护属性,但是在这里指定的保护属性要与CreateFile函数中相对应,如在CreateFile中指定GENERIC_READ,在CreateFileMapping中只能指定PAGE_READONLY;dwMaximumSizeHigh和dwMaximumSizeLow分别是要创建内存映射文件大小的高、低32位值,即内存映射文件大小最大可达180亿GB,当然如要创建成功,必须要有180亿GB物理磁盘空间,实际上这种情况几乎用不到。
内存映射的方式
内存映射的方式内存映射是一种将文件或其他设备映射到程序的内存空间的方式,使得程序可以直接读取或写入内存中的数据,而无需通过繁琐的文件读写操作。
常见的内存映射方式有以下几种:1.文件映射:文件映射是将一个文件的内容映射到内存中,使得程序可以直接访问文件的内容。
文件映射可以分为读映射和写映射两种方式。
读映射意味着程序可以直接从内存中读取文件的内容,而无需通过文件读取操作;写映射则允许程序直接将数据写入到内存中,而无需通过文件写入操作。
文件映射可以提高文件的读写性能,减少了文件操作的开销。
2.共享内存映射:共享内存映射是一种特殊的内存映射方式,它允许多个进程之间共享同一段内存空间。
这种方式可以通过建立映射关系,使得多个进程可以直接读写映射到内存中的数据,实现数据共享和通信。
共享内存映射可以提高进程间通信的效率,避免了复制数据的开销。
3.设备映射:设备映射是将设备的寄存器或者是设备对应的内存空间映射到程序的内存空间中,使得程序可以直接操作设备。
这种方式可以提高对设备的访问效率,并且简化了对设备的操作流程。
提高读写性能:因为内存映射可以减少文件读写操作的次数,直接在内存中进行读写操作,因此可以提高读写性能,特别是对于大文件的读写。
简化操作流程:通过内存映射,程序可以直接访问内存中的数据,而无需通过繁琐的文件读写操作或者设备操作,减少了操作的复杂性和开销。
实现数据共享和通信:共享内存映射可以实现不同进程之间的数据共享和通信,提高了进程间通信的效率。
内存限制:程序的内存空间是有限的,如果映射的文件或设备太大,可能会导致内存不足的问题。
并发访问:如果多个进程或线程同时访问同一段内存映射空间,可能会发生竞争条件和数据一致性问题,需要进行相应的同步和互斥处理。
安全性:内存映射方式对于系统的安全性也有一定的影响,需要特别注意对映射区域的保护和权限控制,防止恶意访问和篡改。
总的来说,内存映射是一种高效简便的数据访问方式,可以提高读写性能,简化操作流程,并实现数据共享和通信。
操作系统中的内存映射与文件映射技术
操作系统中的内存映射与文件映射技术内存映射和文件映射是操作系统中常用的技术之一。
它们允许操作系统将磁盘上的文件直接映射到内存,使得对文件的访问操作可以像对内存一样快速和方便。
本文将分别介绍内存映射和文件映射的原理、应用场景以及它们的优缺点。
一、内存映射1.内存映射的原理内存映射是操作系统中一种将磁盘上的文件映射到进程地址空间的技术。
具体而言,操作系统会为文件在虚拟内存地址空间中分配一段连续的地址,并将文件内容从磁盘读取到这段内存中。
这样,对该文件的访问操作就可以直接在内存中进行,而不需要再通过文件读写系统调用。
2.内存映射的应用场景内存映射在操作系统中有着广泛的应用场景。
其中最常见的应用场景包括:-文件访问:将文件映射到内存中可以避免频繁的磁盘读写操作,从而提高文件访问速度。
这在处理大型文件或需要频繁访问的文件时特别有用。
-共享内存:多个进程可以将同一个文件映射到各自的地址空间中,从而实现共享内存的目的。
这在并发编程和进程间通信中常用,可以提高进程间的数据交换效率。
-动态链接库加载:操作系统可以将动态链接库文件映射到进程地址空间中,实现动态库的加载和使用。
这可以提高程序的可扩展性和灵活性。
3.内存映射的优缺点内存映射技术有着以下优点:-提高访问速度:内存映射将磁盘上的文件映射到内存中,避免了频繁的磁盘读写操作,从而提高了访问速度。
-简化编程:内存映射使得对文件的访问可以像访问内存一样简单,不需要使用繁琐的文件读写系统调用。
-共享数据:多个进程可以通过映射同一文件实现共享内存,从而在进程间交换数据,并实现进程间的通信。
然而,内存映射技术也有以下缺点:-浪费内存:内存映射会为文件在进程地址空间中分配一段内存,如果映射了大型文件,会导致内存的浪费。
-安全性问题:如果多个进程都可以访问同一个文件的映射内存,那么需要注意对共享内存的保护,避免数据损坏或非法访问。
-文件大小限制:由于内存有限,操作系统对单个文件的映射大小通常存在限制,不能超过操作系统的地址空间大小。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
内存映射文件要点:MapViewOfFile函数中映射文件的偏移地址必须为系统分配粒度的整数倍,但一次映射的文件长度则不受此限制。
摘要:本文给出了一种方便实用的解决大文件的读取、存储等处理的方法,并结合相关程序代码对具体的实现过程进行了介绍。
引言文件操作是应用程序最为基本的功能之一,Win32 API和MFC均提供有支持文件处理的函数和类,常用的有Win32 API的CreateFile()、WriteFile()、ReadFile()和MFC提供的CFile类等。
一般来说,以上这些函数可以满足大多数场合的要求,但是对于某些特殊应用领域所需要的动辄几十GB、几百GB、乃至几TB的海量存储,再以通常的文件处理方法进行处理显然是行不通的。
目前,对于上述这种大文件的操作一般是以内存映射文件的方式来加以处理的,本文下面将针对这种Windows核心编程技术展开讨论。
内存映射文件内存映射文件与虚拟内存有些类似,通过内存映射文件可以保留一个地址空间的区域,同时将物理存储器提交给此区域,只是内存文件映射的物理存储器来自一个已经存在于磁盘上的文件,而非系统的页文件,而且在对该文件进行操作之前必须首先对文件进行映射,就如同将整个文件从磁盘加载到内存。
由此可以看出,使用内存映射文件处理存储于磁盘上的文件时,将不必再对文件执行I/O操作,这意味着在对文件进行处理时将不必再为文件申请并分配缓存,所有的文件缓存操作均由系统直接管理,由于取消了将文件数据加载到内存、数据从内存到文件的回写以及释放内存块等步骤,使得内存映射文件在处理大数据量的文件时能起到相当重要的作用。
另外,实际工程中的系统往往需要在多个进程之间共享数据,如果数据量小,处理方法是灵活多变的,如果共享数据容量巨大,那么就需要借助于内存映射文件来进行。
实际上,内存映射文件正是解决本地多个进程间数据共享的最有效方法。
内存映射文件并不是简单的文件I/O操作,实际用到了Windows的核心编程技术--内存管理。
所以,如果想对内存映射文件有更深刻的认识,必须对Windows操作系统的内存管理机制有清楚的认识,内存管理的相关知识非常复杂,超出了本文的讨论范畴,在此就不再赘述,感兴趣的读者可以参阅其他相关书籍。
下面给出使用内存映射文件的一般方法:首先要通过CreateFile()函数来创建或打开一个文件内核对象,这个对象标识了磁盘上将要用作内存映射文件的文件。
在用CreateFile()将文件映像在物理存储器的位置通告给操作系统后,只指定了映像文件的路径,映像的长度还没有指定。
为了指定文件映射对象需要多大的物理存储空间还需要通过CreateFileMapping()函数来创建一个文件映射内核对象以告诉系统文件的尺寸以及访问文件的方式。
在创建了文件映射对象后,还必须为文件数据保留一个地址空间区域,并把文件数据作为映射到该区域的物理存储器进行提交。
由MapViewOfFile()函数负责通过系统的管理而将文件映射对象的全部或部分映射到进程地址空间。
此时,对内存映射文件的使用和处理同通常加载到内存中的文件数据的处理方式基本一样,在完成了对内存映射文件的使用时,还要通过一系列的操作完成对其的清除和使用过资源的释放。
这部分相对比较简单,可以通过UnmapViewOfFile()完成从进程的地址空间撤消文件数据的映像、通过CloseHandle()关闭前面创建的文件映射对象和文件对象。
内存映射文件相关函数在使用内存映射文件时,所使用的API函数主要就是前面提到过的那几个函数,下面分别对其进行介绍:函数CreateFile()即使是在普通的文件操作时也经常用来创建、打开文件,在处理内存映射文件时,该函数来创建/打开一个文件内核对象,并将其句柄返回,在调用该函数时需要根据是否需要数据读写和文件的共享方式来设置参数dwDesiredAccess和dwShareMode,错误的参数设置将会导致相应操作时的失败。
CreateFileMapping()函数创建一个文件映射内核对象,通过参数hFile指定待映射到进程地址空间的文件句柄(该句柄由CreateFile()函数的返回值获取)。
由于内存映射文件的物理存储器实际是存储于磁盘上的一个文件,而不是从系统的页文件中分配的内存,所以系统不会主动为其保留地址空间区域,也不会自动将文件的存储空间映射到该区域,为了让系统能够确定对页面采取何种保护属性,需要通过参数flProtect来设定,保护属性PAGE_READONLY、PAGE_READWRITE和PAGE_WRITECOPY分别表示文件映射对象被映射后,可以读取、读写文件数据。
在使用PAGE_READONLY时,必须确保CreateFile()采用的是GENERIC_READ参数;PAGE_READWRITE则要求CreateFile()采用的是GENERIC_READ|GENERIC_WRITE参数;至于属性PAGE_WRITECOPY则只需要确保CreateFile()采用了GENERIC_READ和GENERIC_WRITE其中之一即可。
DWORD型的参数dwMaximumSizeHigh和dwMaximumSizeLow也是相当重要的,指定了文件的最大字节数,由于这两个参数共64位,因此所支持的最大文件长度为16EB,几乎可以满足任何大数据量文件处理场合的要求。
MapViewOfFile()函数负责把文件数据映射到进程的地址空间,参数hFileMappingObject为CreateFileMapping()返回的文件映像对象句柄。
参数dwDesiredAccess则再次指定了对文件数据的访问方式,而且同样要与CreateFileMapping()函数所设置的保护属性相匹配。
虽然这里一再对保护属性进行重复设置看似多余,但却可以使应用程序能更多的对数据的保护属性实行有效控制。
MapViewOfFile()函数允许全部或部分映射文件,在映射时,需要指定数据文件的偏移地址以及待映射的长度。
其中,文件的偏移地址由DWORD型的参数dwFileOffsetHigh和dwFileOffsetLow组成的64位值来指定,而且必须是操作系统的分配粒度的整数倍,对于Windows操作系统,分配粒度固定为64KB。
当然,也可以通过如下代码来动态获取当前操作系统的分配粒度:参数dwNumberOfBytesToMap指定了数据文件的映射长度,这里需要特别指出的是,对于Windows 9x操作系统,如果MapViewOfFile()无法找到足够大的区域来存放整个文件映射对象,将返回空值(NULL);但是在Windows 2000下,MapViewOfFile()只需要为必要的视图找到足够大的一个区域即可,而无须考虑整个文件映射对象的大小。
在完成对映射到进程地址空间区域的文件处理后,需要通过函数UnmapViewOfFile()完成对文件数据映像的释放,该函数原型声明如下:唯一的参数lpBaseAddress指定了返回区域的基地址,必须将其设定为MapViewOfFile()的返回值。
在使用了函数MapViewOfFile()之后,必须要有对应的UnmapViewOfFile()调用,否则在进程终止之前,保留的区域将无法释放。
除此之外,前面还曾由CreateFile()和CreateFileMapping()函数创建过文件内核对象和文件映射内核对象,在进程终止之前有必要通过CloseHandle()将其释放,否则将会出现资源泄漏的问题。
除了前面这些必须的API函数之外,在使用内存映射文件时还要根据情况来选用其他一些辅助函数。
例如,在使用内存映射文件时,为了提高速度,系统将文件的数据页面进行高速缓存,而且在处理文件映射视图时不立即更新文件的磁盘映像。
为解决这个问题可以考虑使用FlushViewOfFile()函数,该函数强制系统将修改过的数据部分或全部重新写入磁盘映像,从而可以确保所有的数据更新能及时保存到磁盘。
使用内存映射文件处理大文件应用示例下面结合一个具体的实例来进一步讲述内存映射文件的使用方法。
该实例从端口接收数据,并实时将其存放于磁盘,由于数据量大(几十GB),在此选用内存映射文件进行处理。
下面给出的是位于工作线程MainProc中的部分主要代码,该线程自程序运行时启动,当端口有数据到达时将会发出事件hEvent[0],WaitForMultipleObjects()函数等待到该事件发生后将接收到的数据保存到磁盘,如果终止接收将发出事件hEvent[1],事件处理过程将负责完成资源的释放和文件的关闭等工作。
下面给出此线程处理函数的具体实现过程:……// 创建文件内核对象,其句柄保存于hFileHANDLE hFile = CreateFile("Recv1.zip",GENERIC_WRITE | GENERIC_READ,FILE_SHARE_READ,NULL,CREATE_ALWAYS,FILE_FLAG_SEQUENTIAL_SCAN,NULL);// 创建文件映射内核对象,句柄保存于hFileMappingHANDLE hFileMapping = CreateFileMapping(hFile,NULL,PAGE_READWRITE,0, 0x4000000, NULL);// 释放文件内核对象CloseHandle(hFile);// 设定大小、偏移量等参数__int64 qwFileSize = 0x4000000;__int64 qwFileOffset = 0;__int64 T = 600 * sinf.dwAllocationGranularity;DWORD dwBytesInBlock = 1000 * sinf.dwAllocationGranularity;// 将文件数据映射到进程的地址空间PBYTE pbFile = (PBYTE)MapViewOfFile(hFileMapping,FILE_MAP_ALL_ACCESS,(DWORD)(qwFileOffset>>32), (DWORD)(qwFileOffset&0xFFFFFFFF), dwBytesInBlock); while(bLoop){// 捕获事件hEvent[0]和事件hEvent[1]DWORD ret = WaitForMultipleObjects(2, hEvent, FALSE, INFINITE);ret -= WAIT_OBJECT_0;switch (ret){// 接收数据事件触发case 0:// 从端口接收数据并保存到内存映射文件nReadLen=syio_Read(port[1], pbFile + qwFileOffset, QueueLen);qwFileOffset += nReadLen;// 当数据写满60%时,为防数据溢出,需要在其后开辟一新的映射视图if (qwFileOffset > T){T = qwFileOffset + 600 * sinf.dwAllocationGranularity;UnmapViewOfFile(pbFile);pbFile = (PBYTE)MapViewOfFile(hFileMapping,FILE_MAP_ALL_ACCESS,(DWORD)(qwFileOffset>>32), (DWORD)(qwFileOffset&0xFFFFFFFF), dwBytesInBlock); }break;// 终止事件触发case 1:bLoop = FALSE;// 从进程的地址空间撤消文件数据映像UnmapViewOfFile(pbFile);// 关闭文件映射对象CloseHandle(hFileMapping);break;}}…在终止事件触发处理过程中如果只简单的执行UnmapViewOfFile()和CloseHandle()函数将无法正确标识文件的实际大小,即如果开辟的内存映射文件为30GB,而接收的数据只有14GB,那么上述程序执行完后,保存的文件长度仍是30GB。