![]() |
Re: Speichern eines großen Arrays
Zitat:
Hier noch Beispielcode zu meinem Lösungsvorschlag mit einer komprimierten Datei:
Delphi-Quellcode:
uses
Classes, Contnrs; type TVocabulary = class Language1: string; Language2: string; Note: string; AddedOn: TDateTime; LastTraining: TDateTime; Chance: Single; Mistakes: Integer; Trials: Integer; Box: Integer; protected procedure WriteToStream(AStream: TStream); procedure ReadFromStream(AStream: TStream); end; TVocabularyList = class(TObjectList) LanguageName1: string; LanguageName2: string; Note: string; public procedure WriteToStream(AStream: TStream); procedure ReadFromStream(AStream: TStream); end; procedure SaveToFile(AList: TVocabularyList; AFilename: string); procedure LoadFromFile(AList: TVocabularyList; AFilename: string); implementation uses SysUtils, Windows, ZLib; type TFileHeader = record Ident: array[1..10] of Char; procedure WriteToStream(AStream: TStream); procedure ReadFromStream(AStream: TStream); class operator Explicit(v: TFileHeader): string; end; TRecordHeader = record Ident: string; Version: LongWord; procedure WriteToStream(AStream: TStream); procedure ReadFromStream(AStream: TStream); end; const VocabularyIdent_File: TFileHeader = (Ident: ('V','o','c','a','b','u','l','a','r','y')); VocabularyIdent_Header: TRecordHeader = (Ident: 'Header'; Version: $00010000); VocabularyIdent_Items: TRecordHeader = (Ident: 'Items'; Version: $00010000); procedure WriteStringToStream(AStream: TStream; const AValue: string); var c: LongWord; begin c := Length(AValue); AStream.WriteBuffer(c, SizeOf(c)); AStream.WriteBuffer(PChar(AValue)^, c); end; procedure ReadStringFromStream(AStream: TStream; var AValue: string); var c: LongWord; begin AStream.ReadBuffer(c, SizeOf(c)); SetLength(AValue, c); AStream.ReadBuffer(PChar(AValue)^, c); end; procedure TFileHeader.WriteToStream(AStream: TStream); begin AStream.WriteBuffer(Ident, SizeOf(Ident)); end; class operator TFileHeader.Explicit(v: TFileHeader): string; var i: Integer; begin Result := ''; for i := Low(v.Ident) to High(v.Ident) do begin if v.Ident[i] = #0 then Exit; Result := Result + v.Ident[i]; end; end; procedure TFileHeader.ReadFromStream(AStream: TStream); begin AStream.ReadBuffer(Ident, SizeOf(Ident)); end; procedure TRecordHeader.WriteToStream(AStream: TStream); begin WriteStringToStream(AStream, Ident); AStream.WriteBuffer(Version, SizeOf(Version)); end; procedure TRecordHeader.ReadFromStream(AStream: TStream); begin ReadStringFromStream(AStream, Ident); AStream.ReadBuffer(Version, SizeOf(Version)); end; procedure TVocabularyList.WriteToStream(AStream: TStream); var i, c: LongWord; begin {Datei-Inhalt} VocabularyIdent_File.WriteToStream(AStream); {Header} VocabularyIdent_Header.WriteToStream(AStream); WriteStringToStream(AStream, LanguageName1); WriteStringToStream(AStream, LanguageName2); WriteStringToStream(AStream, Note); {Items} VocabularyIdent_Items.WriteToStream(AStream); c := Count; AStream.WriteBuffer(c, SizeOf(c)); for i := 0 to c - 1 do TVocabulary(Items[i]).WriteToStream(AStream); end; procedure TVocabularyList.ReadFromStream(AStream: TStream); {---} procedure CheckRecordHeader(const AValue, AReferenz: TRecordHeader); begin if AValue.Ident <> AReferenz.Ident then raise Exception.CreateFmt('ungültiges Dateiformat, ''%s'' erwartet', [AReferenz.Ident]); end; {---} procedure CheckRecordVersion(const AValue, AReferenz: TRecordHeader); begin if AValue.Ident <> AReferenz.Ident then raise Exception.CreateFmt('ungültige Recordversion ''%s'' V%d.%d', [AValue.Ident, HiWord(AValue.Version), LoWord(AValue.Version)]); end; {---} var i, c: LongWord; FileHeader: TFileHeader; RecordHeader: TRecordHeader; v: TVocabulary; begin LanguageName1 := ''; LanguageName2 := ''; Note := ''; Clear; {Datei-Inhalt} FileHeader.ReadFromStream(AStream); if FileHeader.Ident <> VocabularyIdent_File.Ident then raise Exception.CreateFmt('ungültiges Dateiformat, %s erwartet', [string(VocabularyIdent_File)]); {Header} RecordHeader.ReadFromStream(AStream); CheckRecordHeader(RecordHeader, VocabularyIdent_Header); CheckRecordVersion(RecordHeader, VocabularyIdent_Header); ReadStringFromStream(AStream, LanguageName1); ReadStringFromStream(AStream, LanguageName2); ReadStringFromStream(AStream, Note); {Items} RecordHeader.ReadFromStream(AStream); CheckRecordHeader(RecordHeader, VocabularyIdent_Items); CheckRecordVersion(RecordHeader, VocabularyIdent_Items); AStream.ReadBuffer(c, SizeOf(c)); for i := 0 to c - 1 do begin v := TVocabulary.Create; try v.ReadFromStream(AStream); except v.Free; raise; end; Add(v); end; end; procedure TVocabulary.WriteToStream(AStream: TStream); begin WriteStringToStream(AStream, Language1); WriteStringToStream(AStream, Language2); WriteStringToStream(AStream, Note); AStream.WriteBuffer(AddedOn, SizeOf(AddedOn)); AStream.WriteBuffer(LastTraining, SizeOf(LastTraining)); AStream.WriteBuffer(Chance, SizeOf(Chance)); AStream.WriteBuffer(Mistakes, SizeOf(Mistakes)); AStream.WriteBuffer(Trials, SizeOf(Trials)); AStream.WriteBuffer(Box, SizeOf(Box)); end; procedure TVocabulary.ReadFromStream(AStream: TStream); begin ReadStringFromStream(AStream, Language1); ReadStringFromStream(AStream, Language2); ReadStringFromStream(AStream, Note); AStream.ReadBuffer(AddedOn, SizeOf(AddedOn)); AStream.ReadBuffer(LastTraining, SizeOf(LastTraining)); AStream.ReadBuffer(Chance, SizeOf(Chance)); AStream.ReadBuffer(Mistakes, SizeOf(Mistakes)); AStream.ReadBuffer(Trials, SizeOf(Trials)); AStream.ReadBuffer(Box, SizeOf(Box)); end; procedure SaveToFile(AList: TVocabularyList; AFilename: string); var stream: TStream; begin stream := TFileStream.Create(AFilename, fmCreate); try stream := TCompressionStream.Create(clDefault, stream); AList.WriteToStream(stream); finally stream.Free; end; end; procedure LoadFromFile(AList: TVocabularyList; AFilename: string); var stream: TStream; begin stream := TFileStream.Create(AFilename, fmOpenRead, fmShareDenyWrite); try stream := TDecompressionStream.Create(stream); AList.ReadFromStream(stream); finally stream.Free; end; end; |
Re: Speichern eines großen Arrays
Vielen Dank für das ausführlich Beispiel, aber du du lädst beim Öffnen der Vokabelliste doch alle Vokbabeln in einer Objektliste und die wiederrrum liegt irgendwo im Arbeitsspeicher. Ich wollte aber eigentlich nicht alle Vokabeln in den Arbeitsspeicher laden, da es eigentlich nicht nötig sein würde.
Vielmehr würde mir in den meisten Fällen ein einfacher Zugriff auf eine einzelne Vokabl reichen. Vermutlich kann man auch nur einen bestimmten Abschnitt des Streams laden, aber an der Stelle denk ich ist dann die Datenbank die für mich leichtere Methode... |
Re: Speichern eines großen Arrays
Bloß noch was zum Array, also wenn man die Datenbank nicht möchte.
Delphi-Quellcode:
Die Größe des "reellen Arrays wird dann über Dateigröße/Recordgröße berechnet. (ein Length/High gibt es hier ja nicht)
TVocabulary = record
Language1: String[100]; Language2: String[100]; Note: String[100]; AddedOn: TDateTime; LastTraining: TDateTime; Chance: Single; Mistakes: Integer; Trials: Integer; Box: Integer; end; TVocabularyArray = Array[0..0] of TVocabulary; PVocabularyArray = ^TVocabularyArray; Und jetzt via MMF (Memory Mapped File) die Datei laden und einfach den Array-Pointer drüberlegen. Somit liegt der Großteil der Datei nicht im RAM und es werden nur die Teile automatisch in den Speicher gemappt, auf welche zugegriffen wird. Es belegt zwar im Programm immernoch etwa genauso viel "virtuellen" Speicher, wie das "normale" dynamische Array, aber im Windows wird nur ein Bruchteil das Speichers verbraucht, da große Teile einfach in der Datei verbleiben können. |
Re: Speichern eines großen Arrays
Zitat:
Allerdings hätte es dann auch keine Geschwindigkeitsprobleme mit dem "File of ..." gegeben (ein Memory Mapped File wäre eine elegantere Variante, funktioniert aber auch nicht mit Strings dynamischer Länge). Deshalb befürchte ich, daß die Geschwindigkeitsprobleme durch den Einsatz eines Datenbankservers nicht gelöst werden. Die Daten werden vieleicht nicht in den Arbeitsspeicher deiner Anwendung geladen, aber auf Grund der Art deiner Datenabfragen in den Arbeitsspeicher des Datenbankservers. Aber berichte uns von deinen Erfahrungen, sobald dein Projekt soweit ist. |
Re: Speichern eines großen Arrays
Zitat:
sonst wäre es mit der "file of" auch nicht gegangen. |
Re: Speichern eines großen Arrays
wenn du meinen ersten Post gelesen hättest, wüsstest du das mich dies durchaus stört. Dynamische Array wären mir deutlich lieber ...
Also die Datenstruktur muss im Grunde genommen 3 Aufgaben erfüllen: 1. Vokabelabfrage: Dazu würde ich bei der Datenbank den aktuellen Eintrag einmal in ein TVocabulary laden (mit dynamischen arrays) und beim Wechsel zur nächsten Vokabel dann wieder von TVocabulary in die Datenbank speichern. 2. Vokabelliste bearbeiten: Hier geht es im Wesentlichen darum einen Teil der Vokabeln in einer Listbox oder einem Grid (überleg ich mir dann noch) darzustellen und diese dann über zusätzliche Editfelder zu bearbeiten. Dabei wird in der Regel auch immer nur eine Vokabel geladen (außer beim löschen von mehreren Eintrag gleichzeitig). 3. Statistik: Einfach nur ein paar durchschnittliche Werte (Anzahl Fehler etc.), könnte man entweder jedes mal neu bestimmen oder halt entsprechende Variablen mitführen die man dann immer schön aktuell halten muss. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 15:42 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