delphi中如何将一整个文件读入内存


本文整理自网络,侵删。

 
来源 https://bbs.csdn.net/topics/390985048

分配一块大内存吧,要是一下申请不了64M那么大,就多申请几块小的,用个链表连起来。
用FileStream类的方法读取文件内容。

 

var
strList:TStringList;
begin
strList:=TStringList.Create;
strList.LoadFromFile('Filepath');//这样就读到内存中,保存在变量strList中了,要用的时候可以用strList.text取出
end;
文件流、

var
  mStream: TMemoryStream;
begin
  mStream := TMemoryStream.Create;
  mStream.LoadFromFile('c:\temp\test.txt');          {把文件读入内存流}
  Memo1.Lines.LoadFromStream(mStream);      {把内存流载入 Memo1}
用内存映射最好,TMemoryStream坑爹呢,整个64M到内存去?要是上G文件也这样整?TFileStream比较慢,内存映射最快,大致是CreateFile获得文件句柄,再 CreateFileMapping 创建映射 ,然后根据大小一块一块MapViewOfFile ,得到的内存地址可以直接访问,效率绝对可以。

复制代码
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读进来都不成问题

复制代码
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;
复制代码
C# 读取大文件至内存
复制代码
long offest = 0;
            byte[] buffer = null;
            try
            {
                using (FileStream fs = new FileStream(fileFullPath, FileMode.Open))
                {
                    buffer = new byte[1024 * 1024];
                    while ((offest + 1024 * 1024) <= fs.Length)
                    {
                        fs.Read(buffer, 0, buffer.Length);
                        offest += 1024 * 1024;
                        fs.Seek(offest, SeekOrigin.Begin);
                    }
 
                    
 
                    if ((fs.Length - offest) < 1024 * 1024)
                    {
                        fs.Read(buffer, 0, Convert.ToInt32(fs.Length - offest));
                        MessageBox.Show("Done");
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
复制代码
因为计算机的内存空间是有限的,如果一次性把大数据文件加载至内存,会造成内存极速被消耗。此举不适合一般情况的读取大数据文件。
C#提供了FileStream类来操作文件流,可以和Seek()函数一起循环读取文件中特定长度的数据(比如1M),这样不会造成内存浪费,也符合软件开发的基本逻辑。

相关阅读 >>

Delphi 递归获取文件夹大小

Delphi 7 中的随机函数

Delphi 调用外部 dll 中的函数(1. 早绑定)

Delphi win32_diskdrive 硬盘 参数说明

Delphi获取宽带ip

Delphi从路径中分离文件名

Delphi memo1 字符串快速查找定位

Delphi 判断文件是否存在

Delphi编程用流来读取txt文件中的数据

Delphi 从listview组件中的选定行在数据库中删除

更多相关阅读请进入《Delphi》频道 >>



打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

评论

管理员已关闭评论功能...