Memory mapped soubory v Delphi

vložil Radek Červinka 9. ledna 2010 23:49

Delphi umožňuje různé možnosti pro přístup k souborům (TFileStream, BlockRead, Read atd), ale ještě je možné použít vysoce efektivní přístup přes soubory mapované do paměti (Memory mapped files) za pomoci Windows.

Tento přístup má několik výhod:

  • vysoce efektivní přístup k souborům s HW podporou a cache Windows
  • jednoduchá práce jako s pamětí
  • efektivní nahodilý přístup (základ pro vícevláknové programy)
  • přístup k obrovským souborům (do 4G pro 32 bit Delphi) a přitom soubor není zdaleka celý v paměti

Windows pro tyto případy nabízí tyto API funkce:

  • CreateFileMapping
  • OpenFileMapping
  • MapViewOfFile
  • MapViewOfFileEx
  • UnmapViewOfFile
  • FlushViewOfFile
  • CloseHandle

To je jen pro úplnost, nemá cenu přímo používat API, když JCL nabízí pěkné zapouzdření přes následující třídy z jednotky JclFileUtils.pas:

  • TJclMappedTextReader
  • TJclFileMappingStream
  • TJclFileMapping

Ukáži jednoduchý příklad, spočítání výskytu jednotlivých byte v zadaném souboru.

program mmaptest;
{$APPTYPE CONSOLE}
uses
  SysUtils, JclFileUtils, Windows;

var
  oMappedFile: TJclMappedTextReader;
  aiCounts: array [0..255] of integer;
  i:Integer;
  iTime, iEndTime:Cardinal;
begin
  for i:= 0 to 255 do
    aiCounts[i] := 0;

  iTime := GetTickCount;
  oMappedFile := TJclMappedTextReader.Create('test.txt');
  try
    for i:= 0 to oMappedFile.Size - 1 do
      inc(aiCounts[ord(oMappedFile.Chars[i])]);


    iEndTime := GetTickCount;
  finally
    FreeAndNil(oMappedFile);
  end;

  writeln(Format('Cas: %dms ', [iEndTime - iTime]));

  for i := 0 to 255 do
  begin
    if aiCounts[i] = 0 then
      continue;
    if i < 32 then
      write(format('#%d: %d  ', [i, aiCounts[i]]))
    else
      write(format('"%s": %d  ', [Chr(i), aiCounts[i]]))
  end;
end.

Řádky 29 až do konce vypisují byte s nenulovým výskytem, ale klíčový řádek je 19, kde se využívá property TJclMappedTextReader.Chars. Tato property je implementovaná tak, že vrací byte (přetypovaný na AnsiChar - kompatibilita s Delphi 2009+, pro neunicode Delphi je to Char) z adresy namapovaného souboru. Jak vypadá?

function TJclAnsiMappedTextReader.GetChars(Index: Integer): AnsiChar;
begin
  if (Index < 0) or (Index >= Size) then
    raise EJclError.CreateRes(@RsFileIndexOutOfRange);
  Result := AnsiChar(PByte(FContent + Index)^);
end;

Je vidět, že je to opravdu jen přístup do paměti, tj. opravdu jednoduchá věc.

Ještě jednou opakuji, že výhodou této metody je opravdu jednoduchý přístup a zjednodušení programu (o zrychlení ani nemluvě).

Tagy: ,

Návody

Komentování ukončeno

Naše nabídka

MVP
Ing. Radek Červinka - Embarcadero MVP
profil na linkedin, Twitter:@delphicz

Nabízím placené poradenství a konzultace v oblasti programování a vývoje SW.
Dále nabízíme i vývoj speciálního software na zakázku.

Neváhejte nás kontaktovat (i ohledně reklamy).

Delphi Certified Developer

O Delphi.cz

Delphi je jediný moderní RAD nástroj podporující tvorbu nativních aplikací pro platformu Win32, Win64, Mac OSX a na iPhone a Android.

Delphi.cz je nezávislý portál pro uživatele Delphi. Portál není koncipován pro úplné začátečníky, i když i ti se zde nebudou nudit, ale spíše na programátory, kteří již něco znají a chtějí své znalosti dále rozvíjet a sledovat novinky.

Poslední komentáře

Comment RSS