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

时间:2023-03-08 23:52:26
delphi中如何将一整个文件读入内存

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

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

function FastReadFile(FileName: string): Integer;
const
PAGE_SIZE = * ; //映射块大小不易过大,尽量以4k对齐
var
hFile: THandle;
szHigh,szLow: DWORD;
szFile,ps: Int64;
hMap: THandle;
hData: Pointer;
dwSize: Cardinal;
begin
Result := -;
hFile := ;
hMap := ;
hData := nil;
szHigh := ;
try
//打开已存在的文件,获得文件句柄
hFile := CreateFile(PChar(FileName),GENERIC_READ or GENERIC_WRITE,FILE_SHARE_READ,
nil,OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,);
if hFile = then
begin
Result := GetLastError;
Exit;
end;
//获取文件大小
hMap := ;
hData := nil;
szHigh := ;
szLow := GetFileSize(hFile,@szHigh);
szFile := szLow or (szHigh shl );
//创建映射句柄
hMap := CreateFileMapping(hFile, nil, PAGE_READWRITE, szHigh, szLow, nil);
if hMap = then
begin
Result := GetLastError;
Exit;
end;
ps := ;
//文件可能比较大,分块进行映射
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 ;
//进行映射
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 <> then
CloseHandle(hMap);
if hFile <> then
CloseHandle(hFile);
end;
end;

C# 读取大文件至内存

long offest = ;
byte[] buffer = null;
try
{
using (FileStream fs = new FileStream(fileFullPath, FileMode.Open))
{
buffer = new byte[ * ];
while ((offest + * ) <= fs.Length)
{
fs.Read(buffer, , buffer.Length);
offest += * ;
fs.Seek(offest, SeekOrigin.Begin);
} if ((fs.Length - offest) < * )
{
fs.Read(buffer, , Convert.ToInt32(fs.Length - offest));
MessageBox.Show("Done");
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}

因为计算机的内存空间是有限的,如果一次性把大数据文件加载至内存,会造成内存极速被消耗。此举不适合一般情况的读取大数据文件。
C#提供了FileStream类来操作文件流,可以和Seek()函数一起循环读取文件中特定长度的数据(比如1M),这样不会造成内存浪费,也符合软件开发的基本逻辑。