首页
社区
课程
招聘
[求助]关于内存映射文件的问题,看了核心编程仍然不明原理?
发表于: 2011-8-3 14:37 10131

[求助]关于内存映射文件的问题,看了核心编程仍然不明原理?

2011-8-3 14:37
10131
RT:当映射整个文件的时候没问题,把那几个参数设置成0就OK了。
贴一下测试代码吧
#include "windows.h"
#include<tchar.h>
#include <iostream>

using namespace std;

 

int _tmain(int argc, _TCHAR* argv[])

{

   // Open the file that we want to map.

   // 注意请在c盘,自己创建一个data.txt文件,并写入内容

   HANDLE hFile = ::CreateFile("C:\\data.txt", 

      GENERIC_READ | GENERIC_WRITE, 

      0, 

      NULL,

      OPEN_ALWAYS, 

      FILE_ATTRIBUTE_NORMAL, 

      NULL);

 

   // Create a file-mapping object for the file.

   HANDLE hFileMapping = ::CreateFileMapping(hFile, 

      NULL,

      PAGE_WRITECOPY,

      0, 0,//映射对象的大小,这个大小不晓得有什么作用,麻烦知道的告诉一下,不胜感激,我也改过10等等一些数字,发现无论改多少都不行,必须为0才行,什么情况呢?

      NULL);




   PBYTE pbFile = (PBYTE)::MapViewOfFile(hFileMapping, FILE_MAP_COPY, 0,64*1024, 0);//这里很关键,如果改成0,0(最后两个参数)表示起始映射偏移为0,映射整个文件,我这里设置为64*1024是为了验证这个参数必须是系统分配内存粒度的整数倍,从而达到对齐的效果,这也是MSDN中规定的,当然大家测试的时候可以写成0就行,否则你还得找个大于64K的txt文件来测试,挺累的,哈哈,当我把最后那个参数改成8,也就是我只是想映射8个字节,但是运行出错,IDE VC6.0,麻烦大家测试一下,谢谢了先

   //cout << pbFile << endl;
   FILE *fp;
   fp=fopen("xx.txt","w");

   //fscanf(fp,"%s",pbFile);
   fputs((char *)pbFile,fp);//为了看到结果我故意把输出到了文件中,大家测试的时候可以根据情况
   fclose(fp);

   ::UnmapViewOfFile(pbFile);

 

   ::CloseHandle(hFileMapping);

   ::CloseHandle(hFile);

 

   return 0;

}


问题已经放在代码注释中了,基本上算是2个问题吧,想映射部分(比如8个字节)该如何实现?
文件映射对象的大小有什么作用?为什么我改了好多数都不行呢?MSDN中也没查出个所以然,
其实我把createfilemapping当成是申请内存空间这么理解大家认为对吗,大家是如何理解的,这个映射坦白说看的稀里糊涂的,茫然一片。。。。。。

我对内存映射文件的理解:
一个是(磁盘)文件,一个是视图VIEW(在内存上)
这两个之间需要建立联系,用的就是HMAPFILE文件映射对象建立联系的对吧
比如说磁盘文件内容是 1 2 3 4 5 6
我想映射的内容是 3 4 5
那此时文件映射对象的内容是什么?
他是如何把3 4 5映射到内存中的?

大家看一下下面这个说法是否正确:
使用流程

1 

HANDLE WINAPI CreateFile(
  __in          LPCTSTR lpFileName,
  __in          DWORD dwDesiredAccess,
  __in          DWORD dwShareMode,
  __in          LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  __in          DWORD dwCreationDisposition,
  __in          DWORD dwFlagsAndAttributes,
  __in          HANDLE hTemplateFile
);
参数说明:大家都懂,MSDN。

2 

HANDLE WINAPI CreateFileMapping( __in HANDLE hFile, __in LPSECURITY_ATTRIBUTES lpAttributes, __in DWORD flProtect, __in DWORD dwMaximumSizeHigh, __in DWORD dwMaximumSizeLow, __in LPCTSTR lpName );
参数还是看MSDN吧

这个函数的作用其实是创建一个文件映射内核对象,参数中指定了要占用多少空间,至于这个大家可以这么理解,这个函数的作用其实就是在进程的虚拟地址空间中分配一个指定大小的空间,这个空间的作用下面会说明。返回是一个句柄。

3

LPVOID WINAPI MapViewOfFile(
  __in          HANDLE hFileMappingObject,
  __in          DWORD dwDesiredAccess,
  __in          DWORD dwFileOffsetHigh,
  __in          DWORD dwFileOffsetLow,
  __in          SIZE_T dwNumberOfBytesToMap
);
参数:MSDN

函数作用:将文件中的数据(可以理解成CreateFile打开或者创建的那个文件中的数据)映射到进程地址空间中,疑问:映射多少个空间呢?这个问题在第二部已经解决了,也就是上面说的那个空间,其实就是为这步打基础的。这个函数执行之后,我们可以想象一下是什么情况:

进程的地址空间中现在已经有了一个文件的映射内容,大家都叫这个VIEW视图,这个视图跟在磁盘上的文件建立了映射关系,所以我们就不需要再打开磁盘文件,读取文件。。。。等一系列麻烦的操作了,直接操作这个视图完全OK了,因此此时的情况已经相当于把文件放到了进程地址空间中,如何操作呢,看看此函数的返回值就晓得了,返回的正好就是这个空间中的一个指针。是不是很巧妙。。。。当然了此时对这个视图操作会非常方便,非常简单,速度非常快。。。。。


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 0
支持
分享
最新回复 (14)
雪    币: 158
活跃值: (263)
能力值: ( LV10,RANK:170 )
在线值:
发帖
回帖
粉丝
2
您这个问题,放了1天多, 也没有人回复。我解答一下吧。
在解答之前,您只需要明白2个原则:
1> 应用程序预定地址空间时,系统会确保区域的起始地址正好是分配粒度的整数倍。
2> 应用程序预定地址空间的一块区域时,系统会确保区域大小为系统页面大小的整数倍

假设现在X86~X64的平台使用的分配粒度为 64KB, 然后X86~X64系统使用的页面大小为4KB。
那么计算一下:某应用程序试图预定一块大小为10KB的地址空间区域,那么X86~X64系统会实际分配12KB

有了上面的概念 就好解释你的问题了。

CreateFileMapping 的 参数4 和参数5 是用来表示大小的. 如果你文件大于32位的描述,也就是4GB,那么第4个参数就有用了。 提示你一下: 高低字节
按照你说的,其实在你系统在32位下,设置第5个参数为多少,一般不会有问题。刚刚测试过。

下面解答你的2个问题

想映射部分(比如8个字节)该如何实现?
答: 按照前面说的思路,分配粒度和页面大小的结合, 先预测你的8个字节 在第几个页面,然后按照分配粒度进行MapViewOfFile 就行了。

文件映射对象的大小有什么作用?
答:这个大小的作用其实就是告诉MapViewOfFile这个API可以最大映射多少个字节到地址空间.
2011-8-4 22:13
0
雪    币: 132
活跃值: (214)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
3
上传了一个测试txt,用代码测试了你说的32位系统下第五个参数设置为多少一般都可以,这里我设置了
   // Create a file-mapping object for the file.

   HANDLE hFileMapping = ::CreateFileMapping(hFile, 

      NULL,

      PAGE_WRITECOPY,

      0, 4096*2,//4096也是运行崩溃
      NULL);

PBYTE pbFile = (PBYTE)::MapViewOfFile(hFileMapping, FILE_MAP_COPY, 0,0, 4096);

导致运行崩溃了,这个跟你说的是否矛盾?
文件映射对象的大小有什么作用?
答:这个大小的作用其实就是告诉MapViewOfFile这个API可以最大映射多少个字节到地址空间. 这里我告诉MapViewOfFile最大可以映射4096个字节,并且在MapViewOfFile中也让他映射了4096个字节,但是实际运行却出现内存错误,这里是不是因为4096个字节不在同一个页面上?
上传的附件:
2011-8-5 07:27
0
雪    币: 158
活跃值: (263)
能力值: ( LV10,RANK:170 )
在线值:
发帖
回帖
粉丝
4
你的认真阅读,让我有点意外。 针对 “第5个参数的设置”问题,我没有详细表达。
导致你误解,下面我详细化一些
1> CreateFileMapping 中,你使用的是 PAGE_WRITECOPY 标志位,那么这个标志位表明 你可以在你的data.txt大小范围内设置,比如100 。如果超过data.txt大小范围,就出错。
那么没有可以不限制大小范围呢?有使用 PAGE_READWRITE标志位,具体你可以详细查看文档
2>MapViewOfFile,我的解释,你应该没有问题把。 你还做个实验,可以验证我的想法。 比如你在CreateFileMapping中设置大小为100,那么你在MapViewOfFile 设置4096 会发生什么事情。
2011-8-5 09:07
0
雪    币: 132
活跃值: (214)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
5


   HANDLE hFileMapping = ::CreateFileMapping(hFile, 

      NULL,

      PAGE_READWRITE,

      0, 100,
      NULL);

PBYTE pbFile = (PBYTE)::MapViewOfFile(hFileMapping, FILE_MAP_COPY, 0,0, 4096);

改成这样,出现上述结果,直接挂了。。。。。
2011-8-5 09:32
0
雪    币: 158
活跃值: (263)
能力值: ( LV10,RANK:170 )
在线值:
发帖
回帖
粉丝
6
嗯, 那你明白 了吗?
2011-8-5 09:47
0
雪    币: 132
活跃值: (214)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
7
CreateFileMapping告诉了最大可以映射到是100,这里映射了4096远远超过了100,就崩溃了,但是我在这里把CreateFileMapping设置成4096,然后MapViewOfFile也设成4096依然崩溃呢.....是我哪里没理解到位呢?
2011-8-5 09:53
0
雪    币: 158
活跃值: (263)
能力值: ( LV10,RANK:170 )
在线值:
发帖
回帖
粉丝
8
很抱歉,我这边没有崩溃。 你认真检查一下你的代码~,你也可以选择贴代码~。 不过,我绝对你应该单步跟踪调试,或许并不是 MAPFILE 这组API 出错的。
2011-8-5 09:59
0
雪    币: 132
活跃值: (214)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
9
#include <windows.h>
#include<tchar.h>
#include <iostream>
#include<stdio.h>

using namespace std;

 

int _tmain(int argc, _TCHAR* argv[])

{

   HANDLE hFile = ::CreateFile("C:\\data.txt", 

      GENERIC_READ | GENERIC_WRITE, 

      0, 

      NULL,

      OPEN_ALWAYS, 

      FILE_ATTRIBUTE_NORMAL, 

      NULL);

   HANDLE hFileMapping = ::CreateFileMapping(hFile, 

      NULL,

      PAGE_READWRITE,

      0, 4096,

      NULL);

cout<<GetLastError()<<endl;


   PBYTE pbFile = (PBYTE)::MapViewOfFile(hFileMapping, FILE_MAP_COPY, 0,0, 4096);
   cout<<GetLastError()<<endl;

   cout << pbFile << endl;

调试前面都没错,就最后这里错误cout<<pfFile<<endl;
调试发现pbFile ------------0x003b0000
data.txt中第一个字符数=,如果换成cout<<*pbFile<<endl;则输出为=,这里pbFile指针的值应该就没错,但是怎么cout<<pbFile<<endl;就崩溃呢?
2011-8-5 10:17
0
雪    币: 158
活跃值: (263)
能力值: ( LV10,RANK:170 )
在线值:
发帖
回帖
粉丝
10
嗯,按照现象,已经解决完你的核心问题了。 剩下基本是 C C++ 指针 和 文件操作问题。
这些东西是很基础了,建议自己解决把。
2011-8-5 10:23
0
雪    币: 132
活跃值: (214)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
11
你的没问题,是你的data.txt文件比较小吧,用我的data.txt是会出现问题的,我用的data.txt比4k大了一些,出现问题的原因是真的不清楚,不过找到了一些蛛丝马迹,
#include <windows.h>
#include<tchar.h>
#include <iostream>
#include<stdio.h>

using namespace std;

 

int _tmain(int argc, _TCHAR* argv[])

{

   HANDLE hFile = ::CreateFile("C:\\data.txt", 

      GENERIC_READ | GENERIC_WRITE, 

      0, 

      NULL,

      OPEN_EXISTING, 

      FILE_ATTRIBUTE_NORMAL, 

      NULL);
   cout<<GetLastError()<<endl;

   HANDLE hFileMapping = ::CreateFileMapping(hFile, 

      NULL,

      PAGE_READWRITE,

      0, 4096,

      NULL);

cout<<GetLastError()<<endl;


   PBYTE pbFile = (PBYTE)::MapViewOfFile(hFileMapping, FILE_MAP_COPY, 0,0, 4096);
   cout<<GetLastError()<<endl;
   [COLOR="Red"]pbFile[4095]='\0';[/COLOR]   cout<<pbFile<<endl;

这样就能输出,换成4096就出错,是什么原因导致,莫非是缓冲区的问题?4K的限制?
但是后来又给否定了,
   HANDLE hFileMapping = ::CreateFileMapping(hFile, 

      NULL,

      PAGE_READWRITE,

      0, 5000,

      NULL);

cout<<GetLastError()<<endl;


   PBYTE pbFile = (PBYTE)::MapViewOfFile(hFileMapping, FILE_MAP_COPY, 0,0, 5000);
   cout<<GetLastError()<<endl;
   cout<<pbFile<<endl;

5000不崩溃,4096真的就崩溃了..................我也快崩溃了。。。。。。。。
2011-8-5 11:45
0
雪    币: 90
活跃值: (91)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
占个楼先,一会儿再发表意见
2011-8-5 12:07
0
雪    币: 952
活跃值: (1821)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
这样就能输出,换成4096就出错,是什么原因导致,莫非是缓冲区的问题?4K的限制?
但是后来又给否定了,


....换成4096当然会出错了
数组是从0开始的。4K的数组最大索引是4095...你改成4096不崩才怪呢
2011-8-5 12:44
0
雪    币: 132
活跃值: (214)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
14
你误会了我的意思吧,这里是不是缓冲区的原因还不确定呢?那5000的时候不写怎么也可以输出?
补充:data.txt  大小:4.13kb   4230字节
4096<4230
5000>4230
应该是跟大小有关的吧。.。。。
2011-8-5 12:51
0
雪    币: 210
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
这两个函数还真没有细细追求过,明天来试试。。。
2011-8-7 01:09
0
游客
登录 | 注册 方可回帖
返回
//