频道分类

delphi内存映射 与 映射数据获取

作者:admin 来源: 日期:2019/12/31 8:31:33 人气: 标签:

 
一.原理

    通过使用“内存映射文件”,实现内存共享

二.主要操作

    共享内存结构:

复制代码
复制代码
  PShareMem = ^TShareMem;
  TShareMem = Record
    id:string[10];
    name:string[20];
    age:Integer;
  end;

//  一定要注意 固定长度
复制代码
复制代码
    基本变量:

    shareMemName:string; //共享内存名
    fileHandle : THandle;//内存映射文件句柄
    pUserInfoShareMem : PShareMem;//指向共享内存的指针
    a)写入程序

        1)创建“内存映射文件”

复制代码
复制代码
begin
   //创建“内存映射文件”
   fileHandle:=CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE, 0, SizeOf(TShareMem), PChar(shareMemName));
   if fileHandle <> 0 then
   begin
     Self.Memo1.Lines.Add('已成功创建内存映射文件!');
   end;
end;
复制代码
复制代码
        2)建立映射关系

复制代码
复制代码
  //将“内存映射文件”与“应用程序地址空间”建立映射关系
  pUserInfoShareMem:=MapViewOfFile(fileHandle,FILE_MAP_ALL_ACCESS,0,0,sizeof(TShareMem));
  if pUserInfoShareMem <> nil then
  begin
     Self.Memo1.Lines.Add('已成功建立映射关系!');
  end;
复制代码
复制代码
        3)写入信息

   pUserInfoShareMem.id:='8888';
   pUserInfoShareMem.name:='Terry';
   pUserInfoShareMem.age:=25;
   Self.Memo1.Lines.Add('已向共享内存中写入用户信息!');
        4)解除映射关系

  //解除“内存映射文件”与“应用程序地址空间”的映射关系
  if pUserInfoShareMem<> nil then
     UnmapViewOfFile(pUserInfoShareMem);
  Self.Memo1.Lines.Add('已成功解除映射关系!');
        5)关闭“内存映射文件”

  //关闭内存映射文件
  if fileHandle<> 0 then
     CloseHandle(fileHandle);
  Self.Memo1.Lines.Add('已成功关闭内存映射文件!');
 

    b)读取程序

        1)打开“内存映射文件”

 fileHandle:=OpenFileMapping(FILE_MAP_ALL_ACCESS,false,pchar(shareMemName));
  if self.FileHandle <> 0 then
  begin
    Self.Memo1.Lines.Add('已成功打开内存映射文件!')
  end;
        2)建立映射关系

复制代码
复制代码
   pUserInfoShareMem:= MapViewOfFile(self.FileHandle,windows.FILE_MAP_ALL_ACCESS,0,0,sizeof(TShareMem));
   if pUserInfoShareMem <> nil then
   begin
     Self.Memo1.Lines.Add('已成功建立映射关系!');
   end;
复制代码
复制代码
        3)读取信息

复制代码
复制代码
   if pUserInfoShareMem <> nil then
   begin
      userInfoStr:='共享内存中获取的用户信息如下:'+#13#10;
      userInfoStr:=userInfoStr+'用户Id号:'+pUserInfoShareMem.id+#13#10;
      userInfoStr:=userInfoStr+'用户姓名:'+pUserInfoShareMem.name+#13#10;
      userInfoStr:=userInfoStr+'用户年龄:'+IntToStr(pUserInfoShareMem.age);
      Self.Memo1.Lines.Add(userInfoStr);
   end; 
复制代码
复制代码
        4)解除映射关系

  if pUserInfoShareMem<> nil then
     UnmapViewOfFile(pUserInfoShareMem);
  Self.Memo1.Lines.Add('已成功解除映射关系!');
        5)关闭“内存映射文件”

  if fileHandle<> 0 then
     CloseHandle(fileHandle);
  Self.Memo1.Lines.Add('已成功关闭内存映射文件!');
 

 

 

====================================================

以下 转自 http://blog.csdn.net/bdmh/article/details/6369250
 

procedure TGetDataThread.DoGetData;
var
  FFile_Handle: THandle;
  FFile_Map: THandle;
  list: TStringList;
  p: PChar;
  i, interval: Integer;

begin
  try
    totallen := 0;
    offset := 0;
    tstream := TMemoryStream.Create;
    stream := TMemoryStream.Create;
    list := TStringList.Create;
    // 获取系统信息
    GetSystemInfo(sysinfo);
    // 页面分配粒度大小
    blocksize := sysinfo.dwAllocationGranularity;
    // 打开文件
    FFile_Handle := CreateFile(PChar(FSourceFileName), GENERIC_READ,
      FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
    if FFile_Handle = INVALID_HANDLE_VALUE then
      Exit;
    // 获取文件尺寸
    filesize := GetFileSize(FFile_Handle, nil);
    // 创建映射
    FFile_Map := CreateFileMapping(FFile_Handle, nil, PAGE_READONLY, 0, 0, nil);
    if FFile_Map = 0 then
      Exit;
    // 此处我们已10倍blocksize为一个数据块来映射,如果文件尺寸小于10倍blocksize,则直接映射整个文件长度
    if filesize div blocksize > 10 then
      readlen := 10 * blocksize
    else
      readlen := filesize;
    for i := 0 to FInfoList.Count - 1 do
    begin
      list.Delimiter := ':';
      list.DelimitedText := FInfoList.Strings[i];
      // 取得长度,我这里做了解析,因为我存储的信息为 a:b:c 这种类型,所以以:号分隔
      len := StrToInt(list.Strings[1]);
      interval := StrToInt(list.Strings[2]);
      if (i = 0) or (totallen + len >= readlen) then
      begin
        // 如果已读取的长度加上即将要读取的长度大于 10倍blocksize,那么我们要保留之前映射末尾的内容,以便和新映射的内容合并
        if i > 0 then
        begin
          offset := offset + readlen;
          // 写入临时流
          tstream.Write(p^, readlen - totallen);
          tstream.Position := 0;
        end;
        // 如果未读取的数据长度已经不够一个分配粒度,那么就直接映射剩下的长度
        if filesize - offset < blocksize then
          readlen := filesize - offset;
        // 映射,p是指向映射区域的指针
        // 注意这里第三个参数,一直设为0,这个值要根据实际情况设置
        p := PChar(MapViewOfFile(FFile_Map, FILE_MAP_READ, 0, offset, readlen));
      end;
      // 如果临时流中有数据,需要合并
      if tstream.Size > 0 then
      begin
        // 把临时流数据copy过来
        stream.CopyFrom(tstream, tstream.Size);
        // 然后在末尾写入新数据,合并完成
        stream.Write(p^, len - tstream.Size);
        totallen := len - tstream.Size;
        // 移动指针的位置,指向下一个数据的开始
        Inc(p, len - tstream.Size);
        tstream.Clear;
      end
      else
      begin
        stream.Write(p^, len);
        totallen := totallen + len;
        Inc(p, len);
      end;
      stream.Position := 0;
      // 将流保存成文件
      stream.SaveToFile(IntToStr(i) + '.txt');
      stream.Clear;
    end;
  finally
    stream.Free;
    tstream.Free;
    CloseHandle(FFile_Handle);
    CloseHandle(FFile_Map);
  end;
end;