Delphi 中內(nèi)存映射對于大文件的使用
Delphi 中內(nèi)存映射對于大文件的使用
平時很少使用大文件的內(nèi)存映射,碰巧遇到了這樣的要求,所以把過程記錄下來,當給各位一個引子吧,因為應(yīng)用不算復(fù)雜,可能有考慮不到的地方,歡迎交流。
對于一些小文件,用普通的文件流就可以很好的解決,可是對于超大文件,比如2G或者更多,文件流就不行了,所以要使用API的內(nèi)存映射的相關(guān)方法,即使是內(nèi)存映射,也不能一次映射全部文件的大小,所以必須采取分塊映射,每次處理一小部分。
先來看幾個函數(shù)
CreateFile :打開文件
GetFileSize : 獲取文件尺寸
CreateFileMapping :創(chuàng)建映射
MapViewOfFile :映射文件
看MapViewOfFile的幫助,他的最后兩個參數(shù)都需要是頁面粒度的整數(shù)倍,一般機器的頁面粒度為64k(65536字節(jié)),而我們實際操作中,一般都不是這樣規(guī)矩的,任意位置,任意長度都是可能的,所以就要做一些處理。
本例的任務(wù)是從一個長度列表中(FInfoList),依次讀取長度值,然后到另外一個大文件(FSourceFileName)中去順序讀取指定長度的數(shù)據(jù),如果是小文件,這個就好辦了,一次讀到文件流中,然后依次讀取就是了,大數(shù)對于大文件,就需要不斷改變映射的位置,來取得我們想要的數(shù)據(jù)。
本例中顯示先通過GetSystemInfo來獲取頁面粒度,然后以10倍的頁面粒度為一個映射數(shù)據(jù)塊,在for循環(huán)中,會判斷已經(jīng)讀取的長度(totallen)加上即將讀取的長度,是否在本次映射范圍之內(nèi)(10倍的頁面粒度),如果在就繼續(xù)讀取,如果超出了,就要記下剩下的數(shù)據(jù),然后重新映射下一塊內(nèi)存,并將記錄下的剩余數(shù)據(jù)合并到新讀取的數(shù)據(jù)中,有點繞啊(可能是我的想法太繞了),
下面列出代碼。
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;
//獲取系統(tǒng)信息
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);
//創(chuàng)建映射
FFile_Map := CreateFileMapping(FFile_Handle,nil,PAGE_READONLY,0,0,nil);
if FFile_Map = 0 then Exit;
//此處我們已10倍blocksize為一個數(shù)據(jù)塊來映射,如果文件尺寸小于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,那么我們要保留之前映射末尾的內(nèi)容,以便和新映射的內(nèi)容合并
if i > 0 then
begin
offset := offset + readlen;
//寫入臨時流
tstream.Write(p^,readlen-totallen);
tstream.Position := 0;
end;
//如果未讀取的數(shù)據(jù)長度已經(jīng)不夠一個分配粒度,那么就直接映射剩下的長度
if filesize-offset < blocksize then
readlen := filesize-offset;
//映射,p是指向映射區(qū)域的指針
//注意這里第三個參數(shù),一直設(shè)為0,這個值要根據(jù)實際情況設(shè)置
p := PChar(MapViewOfFile(FFile_Map,FILE_MAP_READ,0,offset,readlen));
end;
//如果臨時流中有數(shù)據(jù),需要合并
if tstream.Size > 0 then
begin
//把臨時流數(shù)據(jù)copy過來
stream.CopyFrom(tstream,tstream.Size);
//然后在末尾寫入新數(shù)據(jù),合并完成
stream.Write(p^,len-tstream.Size);
totallen := len-tstream.Size;
//移動指針的位置,指向下一個數(shù)據(jù)的開始
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;
如有疑問請留言或者到本站社區(qū)交流討論,感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!
上一篇:Delphi解析FTP地址的方法
欄 目:Delphi
下一篇:Delphi實現(xiàn)窗體感知鼠標滑過并自動隱藏與顯示窗口的方法
本文標題:Delphi 中內(nèi)存映射對于大文件的使用
本文地址:http://www.jygsgssxh.com/a1/Delphi/8605.html
您可能感興趣的文章
- 01-10在Delphi實現(xiàn)在數(shù)據(jù)庫中存取圖像的圖文演示無錯
- 01-10delphi建立、讀取、存貯INI文件的方法《三》
- 01-10Delphi Command模式
- 01-10delphi 正弦曲線圖
- 01-10delphi建立、讀取、存貯INI文件的方法《二》
- 01-10插件管理框架 for Delphi(二)
- 01-10插件管理框架 for Delphi(一)
- 01-10Delphi中判斷文件是否為文本文件的函數(shù)
- 01-10delphi中一個值得大家來考慮的DLL問題
- 01-10初探Delphi中的插件編程


閱讀排行
本欄相關(guān)
- 01-10在Delphi實現(xiàn)在數(shù)據(jù)庫中存取圖像的圖
- 01-10delphi建立、讀取、存貯INI文件的方法
- 01-10delphi 正弦曲線圖
- 01-10Delphi Command模式
- 01-10delphi建立、讀取、存貯INI文件的方法
- 01-10插件管理框架 for Delphi(二)
- 01-10插件管理框架 for Delphi(一)
- 01-10Delphi中判斷文件是否為文本文件的函
- 01-10delphi中一個值得大家來考慮的DLL問題
- 01-10初探Delphi中的插件編程
隨機閱讀
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 08-05DEDE織夢data目錄下的sessions文件夾有什
- 01-10C#中split用法實例總結(jié)
- 08-05dedecms(織夢)副欄目數(shù)量限制代碼修改
- 01-11ajax實現(xiàn)頁面的局部加載
- 04-02jquery與jsp,用jquery
- 01-10delphi制作wav文件的方法
- 01-10使用C語言求解撲克牌的順子及n個骰子
- 08-05織夢dedecms什么時候用欄目交叉功能?
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文


