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 MemoryMapped File Zugriff auf großes XML File... (https://www.delphipraxis.net/141355-memorymapped-file-zugriff-auf-grosses-xml-file.html)

pertzschc 7. Okt 2009 18:02


MemoryMapped File Zugriff auf großes XML File...
 
Hallo zusammen,
ich habe ein ziemlich großes XML File, welches ich mittels MMF häppchenweise einem SAX Parser unterschieben möchte. D.h. der SAX Parser bekommt einen Puffer und geht dann Char für Char weiter beim Parsen. Den Puffer möchte ich aus einem MMF bedienen, so dass nicht immer das komplette File in den RAM geladen wird. Ich habe mir dazu mal 2 Methoden erstellt, die rudimentär den Zugriff machen sollen.
Mein Problem ist, dass hFile immer 0 ist. Woran könnte es liegen?

Danke+Gruß,
Christoph

Delphi-Quellcode:
function TForm1.ReadFromMMF(Filename: PChar; Len: Int64): Pointer;
var
  hFile: Cardinal;
begin
  hFile := CreateFileMapping($FFFFFFFF, nil, PAGE_READONLY, 0, Len, Filename); // das geht immer schief, file existiert aber auf platte!
  if hFile <> 0 then
  begin
    try
      Result := MapViewOfFile(hFile, FILE_MAP_READ, 0, 0, 0);
    finally
      //CloseHandle(hFile);
    end;
  end
    else
  begin
    Result := nil;
  end;
end;
procedure TForm1.btn1Click(Sender: TObject);
var
  CurrTxt: PChar;
  FileName, Msg: string;
begin
// lade xml file..
  FileName := ExtractFilePath(Application.ExeName) +'liste_cmg.xml';
  CurrTxt := Self.ReadFromMMF(PChar(FileName), 2000);
// nachfolgend nur dummycode, später zuweisung auf buffer des SAX Parsers
  if Assigned(CurrTxt) then
    begin
      StrLCopy(PChar(Msg),CurrTxt, 10);
      ShowMessage(Msg);
//      CopyMemory(CurrTxt, Data, Len);
    end;
end;

himitsu 7. Okt 2009 18:12

Re: MemoryMapped File Zugriff auf großes XML File...
 
Du solltest vielleicht nochmal die Hilfe zu MSDN-Library durchsuchenCreateFileMapping durchgehn.

Die Datei wird da nicht direkt im letzen Parameter übergeben!
Öffne der Datei mit MSDN-Library durchsuchenCreateFile und übergibt CreateFileMapping im 1. Parameter das Datei-Handle.


[add]
aber ganz im Ernst ... nach dem Durchsehn der Unit LibXmlParser.pas kann ich nur eines Sagen

Es wäre einfacher den Puffer direkt zu laden (MMF ist hier garnicht nötig und viel zu umständlich),
aber es ist nahezu unmöglich dieser Komponente einen sich bewegenen Puffer unterzuschmuggeln und so die speicherbedingte Größenbegrenzung zu umgehen.

"sich bewegend" = da du den Puffer nur an bestimmten (freien) Stellen im Arbeitsspeicher ablegen kannst und somit, beim Nachladen weiterer Daten, die Zugriffszeiger (Pointer) jedesmal anpassen mußt.

Probleme:
- es gibt nicht nur einen zentralen Zeiger (sondern viele kleiner und teilweise sind das lokale Funktions-Parameter
- du hast keine richtige Kontrollmöglichkeit, um zu prüfen wo im Puffer die Funktionen im Moment wirklich sind und welche Daten nun entfernt werden können und (wichtiger) welche Daten noch nötig sind


PS: Ich hab selber Monate gebraucht, bis mein System zum Nachladen der Daten halbwegs lief und hab die ganzen Parsingfunktionen auch daraufhin ausgelegt.
Du willst hier soein System nachrüsten und das in eine Struktur, welche darauf nicht ausgelegt ist und an vielen Stellen sogar ein solches System nicht (oder nur mit größerem Aufwand) unterstützen würde.

pertzschc 7. Okt 2009 19:08

Re: MemoryMapped File Zugriff auf großes XML File...
 
Zitat:

Zitat von himitsu
Du solltest vielleicht nochmal die Hilfe zu MSDN-Library durchsuchenCreateFileMapping durchgehn.

Danke für den Tipp, das hat geholfen.

Zitat:

Zitat von himitsu
aber ganz im Ernst ... nach dem Durchsehn der Unit LibXmlParser.pas kann ich nur eines Sagen
Es wäre einfacher den Puffer direkt zu laden (MMF ist hier garnicht nötig und viel zu umständlich),

Nun das verstehe ich nicht ganz. Du kannst dem XMLScanner mittels SetBuffer() einen Pointer geben und das LoadFile weglassen.

Ich hatte es so verstanden, dass ich mittels MMF bei Zugriff auf jenseits der geladen Chars im Buffer automatisch weitere nachgeladen bekomme.
Ist das falsch? Warum also nicht den Pointer mittels MMF bereitstellen?

Gruß,
Christoph

himitsu 7. Okt 2009 20:19

Re: MemoryMapped File Zugriff auf großes XML File...
 
Du kannst im so einen GANZEN Puffer geben, aber wenn du vor hast via MMF die Daten "stückchenweise" Nachzuladen, dann geht das dann nicht mehr.

Es sei denn du mappst die komplette MMF in den Arbeitsspeicher und übergibst davon den Pointer, aber dann hast du nichts gekommt, da du dann wieder allles an einem Stück haben mußt, womit du ja auch so schon Probleme hast.

Du müßtest also erstmal nur einen Teil der Datei mappen, dieses vom Parser parsen lassen und sobald der Parser an das Ende dieses Stücks kommt, müßtest du den nächten Teil der Datei in den Speicher mappen und den letzen vorher Teil entladen (damit du wieder genügend Speicher hast)

Dafür müßtest du aber erstmal wissen, wann der Parser das Ende dieses Stücks erreicht, den Parser dort anhalten lassen,
den Speicher ändern und die neuen Teile nachladen,
dann die ganze Zeiger auf die Positionen im neuen Speicher verschieben
und ab da den Parser weiterlaufen lassen, bis er wieder das Ende dieses Speicherblocks erreicht hat oder das komplette Ende der Datei.

Dieser Parser ist aber so ausgelegt, daß er zwischendurch nicht in einem definierten Zustand anhält, sondern nonstop bis zum Dateiende ließt.

Du hast es also nicht leicht den Parser definiert anhalten zu lassen, wenn er das Blockende erreicht. (das dürfte sich aber noch relativ leicht ändern lassen, da er ja schön sequentiell/linear arbeitet)
Den Speicher austauschen dürfte noch leicht fallen, wenn man es sich einfach macht un die Blockgrößen begrenzt (also die maximale Länge der Nodes, Attribute und vom NodeText).
Aber nun kommt das Schwierige ... jetzt mußt du "alle" Zeiger auf den neuen Speicher verschieben
und davon gibt es hier genügend.

Das ist schließlich der Grund, warum fast alle XML-Parser nur an einem Stück lesen, weil dieses einfach einfach ist.


Wie gesagt, ich hab bei meinem Parser schon viel Zeit reinstecken müssen, um da ein funktionales System zu entwickeln. Und ich hab auch extra den Parser dafür ausgelegt, daß er eben an bestimmten Stellen einen ganz fest definierten Zustand einnimmt, wo ich dann leicht an der Speicherverwaltung rumspielen kann.

Du kannst ja gern mal in meine Units reinsehn.
In der neuen Version (beta) hab ich das alles jetzt mal abgekapselt und in die eigenständige Klasse TXReader (unit himXML.pas) verfrachtet und diese Klasse ist praktisch nur mit der Speicherverwaltung beschäftigt (bis auf die Funktion .Parse und die Hilfsprozedur .CloseSingleNode) ... also das Nachladen, Freigeben und Zerlegen der Daten.


Alle Zeitangaben in WEZ +1. Es ist jetzt 02:31 Uhr.

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