问题:delphi中如何将一整个文件读入内存,文件大小有64M
描述:

如题,请高手赐教。谢谢!!!


解决方案1:

GetMem(q,43800000);你没检查q的内存是否申请成功了,没申请成功,你后面的操作都是无效的,因为你所要的内存比较大,有时不见得能成功申请到
申请成功且文件又成功读到你分配的内存后,下面一句也可能会有问题的
Memo1.Lines.Add(Format('文件:%s',[BytesToString(@q)]));
60多M的数据,你转成可见字符,一般可能是hex格式,容量至少加一倍,那就是近120M,默认的memo能显示得了?你可以用用xp的记事本打开50m的文件看看,能打开不
我猜想你大致想把文件内容在memo中展示出来,不过这个思路即便能成功,可是你使用起来很费时,加载及显示都比较慢,而且内存分配也有问题,没有特殊必要不会太夸张的进行内存申请;
用filestream其实也可以,你也不用申请那么大的内存,你界面上能看到的可能也就几行,你可以做个游标,要看哪一部分时,把stream.pos移动一下,只转换很小的一部分显示出来即可,这样速度也快,编程起来也不麻烦
基本功能实现了调优的话可以用内存映射,winhex就是内存映射整的

解决方案2:

7楼补充了我遗漏的创建文件句柄
核心还是内存映射
我给出的有何不对之处?
我用$FFFFFFFF做了文件句柄,这里如何得到文件句柄,我想愿意学的话很容易找到方法吧

解决方案3:

六楼的不对,你那个是内存共享映射,不是文件读取,不过代码也差不多类似,我粗略做了个函数,建议封成类,使用更灵活,64M 用TFileStream其实也可以,可能没内存映射快。


function FastReadFile(FileName: string): Integer;
const
  PAGE_SIZE = 4 * 1024; //映射块大小不易过大,尽量以4k对齐
var
  hFile: THandle;
  szHigh,szLow: DWORD;
  szFile,ps: Int64;
  hMap: THandle;
  hData: Pointer;
  dwSize: Cardinal;
begin
  Result := -1;
  hFile := 0;
  hMap := 0;
  hData := nil;
  szHigh := 0;
  try
    //打开已存在的文件,获得文件句柄
    hFile := CreateFile(PChar(FileName),GENERIC_READ or GENERIC_WRITE,FILE_SHARE_READ,
      nil,OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,0);
    if hFile = 0 then
    begin
      Result := GetLastError;
      Exit;
    end;
    //获取文件大小
    hMap := 0;
    hData := nil;
    szHigh := 0;
    szLow := GetFileSize(hFile,@szHigh);
    szFile := szLow or (szHigh shl 32);
    //创建映射句柄
    hMap := CreateFileMapping(hFile, nil, PAGE_READWRITE, szHigh, szLow, nil);
    if hMap = 0 then
    begin
      Result := GetLastError;
      Exit;
    end;
    ps := 0;
    //文件可能比较大,分块进行映射
    while ps < szFile do
    begin
      //计算映射大小及位置
      if szFile - ps > PAGE_SIZE then
        dwSize := PAGE_SIZE
      else
        dwSize := szFile - ps;
      szLow  := ps and $FFFFFFFF;
      szHigh := ps shr 32;
      //进行映射
      hData := MapViewOfFile(hMap,FILE_MAP_ALL_ACCESS,szHigh,szLow,dwSize);
      if hData = nil then
        Break;
      try
        //此时文件偏移ps处的数据通过hData即可读取到,块大小为dwSize
        //以下加上你读取的代码,可以做一个回调函数
        //比如你要当前位置的数据(取文件数)拷到指定内存处 CopyMemory(目标地址指针,hData,dwSize);
        //
      finally
        //移动文件偏移位置
        ps := ps + dwSize;
        //释放映射块
        UnmapViewOfFile(hData);
        hData := nil;
      end;
    end;
  finally
    //释放必要资源
    if hData <> nil then
      UnmapViewOfFile(hData);
    if hMap <> 0 then
      CloseHandle(hMap);
    if hFile <> 0 then
      CloseHandle(hFile);
  end;
end;
解决方案4:


PShareMem = ^TShareMem;
  TShareMem = Record
    id:string[10];
    name:string[20];
    age:Integer;
  end;
  
  shareMemName:string; //共享内存名
    fileHandle : THandle;//内存映射文件句柄
    pUserInfoShareMem : PShareMem;//指向共享内存的指针
begin
   //创建“内存映射文件”
   fileHandle:=CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE, 0, SizeOf(TShareMem), PChar(shareMemName));
   if fileHandle <> 0 then
   begin
     Self.Memo1.Lines.Add('已成功创建内存映射文件!');
   end;
end;
//将“内存映射文件”与“应用程序地址空间”建立映射关系
  pUserInfoShareMem:=MapViewOfFile(fileHandle,FILE_MAP_ALL_ACCESS,0,0,sizeof(TShareMem));
  if pUserInfoShareMem <> nil then
  begin
     Self.Memo1.Lines.Add('已成功建立映射关系!');
  end;
  
  
  pUserInfoShareMem.id:='8888';
   pUserInfoShareMem.name:='Terry';
   pUserInfoShareMem.age:=25;
   Self.Memo1.Lines.Add('已向共享内存中写入用户信息!');
   
   //解除“内存映射文件”与“应用程序地址空间”的映射关系
  if pUserInfoShareMem<> nil then
     UnmapViewOfFile(pUserInfoShareMem);
  Self.Memo1.Lines.Add('已成功解除映射关系!');
  
  //关闭内存映射文件
  if fileHandle<> 0 then
     CloseHandle(fileHandle);
  Self.Memo1.Lines.Add('已成功关闭内存映射文件!');

用内存映射吧, 64G读进来都不成问题

上一篇怎么让delphi一次按钮点击触发其他多个按钮点击(这些按钮都是动态生成的bitbtn,没有caption)
下一篇delphi xe7 自带的JSON问题请教
明星图片
相关文章
《delphi中如何将一整个文件读入内存,文件大小有64M》由码蚁之家搜集整理于网络,
联系邮箱:mxgf168#qq.com(#改为@)