Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi Memory Mapped Files (https://www.delphipraxis.net/891-memory-mapped-files.html)

Luckie 21. Sep 2002 02:36


Memory Mapped Files
 
Hallo Leute,
man hat mir gesagt, dass mein FileSplitter mit Memory Mapped Files schneller arbeiten würde.
Jetzt wollte ich mich mal darüber schlau machen, habe aber im Intern nicht richtiges gefunden. Könnte mir mal jemand etwas auf die Sprünge helfen, wie man mit Memory Mapped Files arbeitet bzw konkret Dateien aufteilt und wieder zusammen fügt?

Christian Seehase 21. Sep 2002 03:03

Moin Luckie,

da Du ja PSDK geübt bist, kann ich Dir, vorerst einmal, mit den benötigten APIs aushelfen.

Das wären zum einen CreateFileMapping, um ein entsprechendes Objekt zu erzeugen, dann MapViewOfFile, um die Datei in den Speicher des Programmes einzublenden. Dabei wird die Datei nicht geladen.
Wenn die Arbeit getan ist, kann mit UnmapViewOfFile das Objekt wieder freigegeben werden.

Da die Memory Mapped Files eigentlich dazu gedacht sind auf Teile einer Datei zuzugreifen, ohne die gesamte Datei lesen zu müssen (z.B. wenn ein grosses Dokument geladen werden soll, kann physikalisch erst einmal der Teil geladen werden, der auch sichtbar ist, erst wenn gescrollt wird, wird, physikalisch, nachgeladen), Du aber für Deinen FileSplitter eh' die ganze Datei lesen musst, habe ich nur meine Zweifel, dass diese Technik Dein Programm schneller macht, ausser die Datei ist sehr gross, und der reale Speicher sehr klein, so dass die Datei nicht auf einmal in den (realen!) Arbeitsspeicher passt, und die Auslagerungsdatei benutzt werden muss.

Christian Seehase 21. Sep 2002 21:12

Moin Luckie,

ich hab' das ganze mal in ein einfaches Objekt gepackt:

Code:
[b]uses[/b] windows,sysutils;

[b]type[/b]
  TcsMMFDemo = [b]class[/b](TObject)
  [b]private[/b]
    FdwReadSize : DWORD;
    FdwPosition : DWORD;
    FszBuffer   : PChar;
    FdwFileSize : DWORD;
    [b]procedure[/b] SetPosition([b]const[/b] Value: DWORD);
  [b]public[/b]
    [b]constructor[/b] Create([b]const[/b] p_sFilePath : [b]string[/b]);
    [b]destructor[/b] Destroy; override;
    [b]function[/b] ReadMMF([b]const[/b] p_dwSize: DWORD;[b]var[/b] p_dwBytesRead : DWORD) : [b]string[/b];
    [b]property[/b] Position : DWORD read FdwPosition write SetPosition;
    [b]property[/b] Size    : DWORD read FdwFileSize;
  [b]end[/b];

[b]implementation[/b]

[color=#000080]{ TcsMMFDemo }[/color]

[b]constructor[/b] TcsMMFDemo.Create([b]const[/b] p_sFilePath: [b]string[/b]);

[b]var[/b]
  aSA   : TSecurityAttributes;
  dwSize : DWORD;
  hFile : DWORD;
  hMMF  : DWORD;

[b]begin[/b]
  [b]inherited[/b] Create;
  aSA.nLength       := SizeOf(TSecurityAttributes);
  aSA.bInheritHandle := true;
  aSA.lpSecurityDescriptor := [b]nil[/b];
  hFile             := CreateFile(PChar(p_sFilePath),GENERIC_READ,FILE_SHARE_READ,@aSA,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
  [b]try[/b]
    [b]if[/b] hFile = INVALID_HANDLE_VALUE [b]then[/b]
    [b]begin[/b]
      [b]raise[/b] Exception.CreateFmt('Datei %s konnte nicht geöffnet werden',[p_sFilePath]);
    [b]end[/b];
    FdwFileSize := GetFileSize(hFile,[b]nil[/b]);
    hMMF       := CreateFileMapping(hFile,@aSA,PAGE_READONLY [b]or[/b] SEC_COMMIT,0,FdwFileSize,[b]nil[/b]);
    [b]if[/b] hMMF = 0 [b]then[/b]
    [b]begin[/b]
      [b]raise[/b] Exception.Create('File Mapping fehlgeschlagen');
    [b]end[/b];
  [b]finally[/b]
    CloseHandle(hFile);
  [b]end[/b];
  FdwPosition := 0;
  FszBuffer   := MapViewOfFile(hMMF,FILE_MAP_READ,0,0,FdwFileSize);
  [b]try[/b]
    [b]if[/b] FszBuffer = [b]nil[/b] [b]then[/b]
    [b]begin[/b]
      [b]raise[/b] Exception.Create('View Mapping fehlgeschlagen');
    [b]end[/b];
  [b]finally[/b]
    CloseHandle(hMMF);
  [b]end[/b];
[b]end[/b];

[b]destructor[/b] TcsMMFDemo.Destroy;
[b]begin[/b]
  UnmapViewOfFile(FszBuffer);
  [b]inherited[/b] Destroy;
[b]end[/b];

[b]procedure[/b] TcsMMFDemo.SetPosition([b]const[/b] Value: DWORD);
[b]begin[/b]
  [b]if[/b] Value < FdwFileSize [b]then[/b]
  [b]begin[/b]
    FdwPosition := Value;
  [b]end[/b]
  [b]else[/b]
  [b]begin[/b]
    FdwPosition := FdwFileSize-1;
  [b]end[/b];
[b]end[/b];

[b]function[/b] TcsMMFDemo.ReadMMF([b]const[/b] p_dwSize: DWORD;[b]var[/b] p_dwBytesRead : DWORD) : [b]string[/b];

[b]begin[/b]
  Result := '';
  [b]if[/b] p_dwSize = 0 [b]then[/b]
  [b]begin[/b]
    exit;
  [b]end[/b];
  FdwReadSize := p_dwSize;
  [b]if[/b] (FdwPosition + FdwReadSize) > FdwFileSize [b]then[/b]
  [b]begin[/b]
    FdwReadSize := FdwFileSize - FdwPosition;
  [b]end[/b];
  p_dwBytesRead := FdwReadSize;
  Result       := StringOfChar(#00,FdwReadSize);
  StrLCopy(@Result[1],(FszBuffer+FdwPosition),FdwReadSize);
  FdwPosition  := FdwPosition + FdwReadSize;
[b]end[/b];

[b]end[/b].
Via Create wird ein Memory Mapped File erzeugt, über die Eigenschaft Position kann man dann angeben, von wo aus das Lesen Starten soll, und mit Read schliesslich wird dann gelesen. Read gibt einem im zweiten Parameter zurück, wieviel gelesen wurde.
Ich hab's hier mal für Textdateien gebaut, aber das sollte sich einfach ändern lassen.

Ich hab's jetzt nicht bis ins letzte ausgetestet, aber bislang hat's funktioniert.

Luckie 21. Sep 2002 21:16

Hei, danke Christian. So viel hatte ich gar nicht erwartet. :P Ich hatte es mir gerade überlegt, ob ich es nach deinem ersten Posting weiterverfolge.

Aber ich werde es mir auf jeden Fall ankucken. :P

jbg 21. Sep 2002 22:09

Die JCL (Jedi Code Library) enthält ebenfalls MMF Klassen.

Luckie 21. Sep 2002 22:31

Danke für den Hinweis, aber ich wollte nicht von Fremdkomponenten abhängig sein.


Alle Zeitangaben in WEZ +1. Es ist jetzt 23:17 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz