Entwickler-Ecke
Dateizugriff - Viele(!) Wahrheitswerte in Datei speichern
P@u1 - Do 15.04.10 18:14
Titel: Viele(!) Wahrheitswerte in Datei speichern
Hallo DF,
wie speichere ich am besten sehr viele (mehrere Millionen) Wahrheitswerte in eine Datei ab?
Habe bisher die Idee gehabt als 1en und 0en in ne text datei zu packen oder evtl die 1en und 0en vorher noch ins 16 oder 10er system umzuwandeln (um die dateigröße zu reduzieren)
Das einlesen wird dadurch aber wahrscheinlich relativ langsam.
Wenn ich das als 1en und 0en in ne text datei schreibe hat die die 8-fache größe von dem was ich erwartet hätte (ich denke er nimmt ein byte für jedes bit...)
Also wie sollte ich am besten vorgehen?
Hoffe das ist hier richtig und kommt nicht in datenbank rein^^
Edit: Wichtig ist auch noch, wie und in was für ein Objekt ich das am besten reinlese.
Edit2: Falls das wichtig ist: Es geht um ca. 26 Millionen Wahrheitswerte
jfheins - Do 15.04.10 18:20
Ein Byte pro Wahrheitswert ist voll okay. Eine 2 Megabyte-Datei ist heutzutage nichts besonderes mehr ;)
Du kannst natürlich auch ein bit pro Wert nehmen, das ist dann halt so klein wie möglich. Aber auch aufwändiger zu lesen und zu schreiben (Klassischer Space vs. Time Tradeoff)
P@u1 - Do 15.04.10 18:22
wie kann ich das denn im bit-format abspeichern?
hätte lieber ca.3 MB größe als 26 MB
jfheins - Do 15.04.10 18:25
Wie hast du die Daten denn vorliegen? Als Boolean Array?
P@u1 - Do 15.04.10 18:27
ich hab sie noch gar nicht vorliegen, ich generiere die selbst, aber boolean-array habe ich bisher benutzt.
wenn es nen besseres format gibt, würde ich evtl auch das nehmen.
Wichtig zu wissen wäre dann noch wie ich das am besten laden kann, also ich kenne bisher leider nur den weg über eine stringlist o.ä. die sachen reinzuladen und dann zu konvertieren, wäre besser es direkt in ein bool-array wieder reinladen zu können
Vielen Dank für deine Hilfe!
jfheins - Do 15.04.10 18:39
Dann geht das ungefähr so:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| procedure SaveToFile(const array) var Bytearray: Array of Byte; begin setlength(Bytearray, Ceil(length(array)/8)); for i := 0 to high(array) do begin if array[i] then Bytearray[i div 8] = Bytearray[i div 8] or (1 shl (i mod 8)); end; end; |
Das ist jetzt nur so schnell hingeschriben, es geht bestimmt auch noch etwas schneller (Über das bytearray iterieren und immer gleich 8 Bools zusammen speichern) ist dann aber komplizierter, falls die Anzahl deiner Wahrheitswerte nicht glatt durch 8 teilbar ist.
ALF - Do 15.04.10 18:40
Hi, Du kannst doch auch das als 32, 64 bit Werte speichern und beim auslesen wieder die einzelnen bits in Boolean werte lesen. Nachteil, du kannst unter Umständen die Werte in der Text Datei nicht entziffern.
Gruss Alf
P@u1 - Do 15.04.10 18:48
jfheins hat folgendes geschrieben : |
Dann geht das ungefähr so:
Delphi-Quelltext 1: 2:
| if array[i] then Bytearray[i div 8] = Bytearray[i div 8] or (1 shl (i mod 8)); |
|
kanns sein, dass vor dem gleich ein doppelpunkt fehlt? wenn nicht, dann versteh ich das schon von der syntax nicht, ansonsten versteh ich einige befehle davon auch nicht, aber ich werds mir gleich nochmal genauer angucken
@ALF: Das sagt mir leider nicht so viel, ich weiß weder wie das geht, noch was das bringt :D
Edit: Das größte Problem ist, ich weiß bisher nur wie man dateien als .txt speichert. ich werd aber jetzt mal nen bischen suchen wie das mit anderen formaten geht
jfheins - Do 15.04.10 19:02
ja, das ist eine Zuweisung (also muss ein Doppelpunkt hin) - aber der Code wird so wie er da steht eh nicht kompilieren. Vielmehr ist es ein in Pseudocode gegossener Gedankengang ;)
P@u1 - Do 15.04.10 19:04
wie und in welchem format speicher ich dann denn das byte array am besten ab?
Edit: Ceil und shl sind mir unbekannt
ALF - Do 15.04.10 19:09
im Prinzip das was @jfheins schon geschrieben hat.
Beispiel:
1010001001011001011101011110011 das sind 32 boolean Werte = binärzahl
12113135363 entspricht einem Oktalwert
1361885939 oder Dezimalzahl
512CBAF3 bzw Hexwert
Du siehst damit kannst Du dann platzt in der Datei sparen.
Um das so umzuwandeln muss ich selbst mal schauen, schon lange her :?
Gruss Alf
P@u1 - Do 15.04.10 19:37
heißt 32 bzw 64 bit dann das ich die zahl ins 32er /64er system umwandle? soviele buchstaben gibts dann doch gar nicht :D
das hatte ich am anfang ja auch schon vorgeschlagen,
aber dass wird das einlesen verlangsamen (muss noch konvertiert werden).
Und Soll das dann in einer txt datei gespeichert werden oder besser was anderes?
Martok - Do 15.04.10 19:51
Mal ein anderer Ansatz:
Schreib die Daten so wie sie kommen, von mir aus auch als Bytes, und jage das Ganze durch einen CompressionStream (zlib also).
Solange irgendwelche Muster (=mehrere gleiche Werte o.ä.) drin sind, ist das effektiver als sich unglaublich komplizierte Algorithmen zur Datenverpackung zu bauen.
Zumal du früher oder später dann eh bei Run-Length-Encoding landen würdest, wenn du weiter optimierst ;)
Narses - Do 15.04.10 20:09
Moin!
Suchst du sowas? ;)
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125:
| unit BitVektor;
interface
uses SysUtils, Classes;
const MAGIC = AnsiString('NBVF');
type TBitVektor = class(TObject) private FCapacity: Integer; FData: array of LongWord; procedure SetCapacity(const Value: Integer); function GetBit(const AIndex: Integer): Boolean; procedure SetBit(const AIndex: Integer; const Value: Boolean); public constructor Create(const InitialCapacity: Integer = 32); destructor Destroy; override; property Capacity: Integer read FCapacity write SetCapacity; property Bit[const AIndex: Integer]: Boolean read GetBit write SetBit; procedure Clear; procedure WriteToStream(AStream: TStream); procedure ReadFromStream(AStream: TStream); procedure SaveToFile(const AFileName: String); procedure LoadFromFile(const AFileName: String); end;
implementation
procedure TBitVektor.Clear; var i: Integer; begin for i := 0 to High(FData) do FData[i] := 0; end;
constructor TBitVektor.Create(const InitialCapacity: Integer = 32); begin inherited Create; SetCapacity(InitialCapacity); end;
destructor TBitVektor.Destroy; begin FData := NIL; inherited; end;
function TBitVektor.GetBit(const AIndex: Integer): Boolean; begin Result := (FData[AIndex shr 5] and (1 shl (AIndex and 31))) <> 0; end;
procedure TBitVektor.LoadFromFile(const AFileName: String); var FS: TFileStream; begin FS := TFileStream.Create(AFileName,fmOpenRead or fmShareDenyWrite); try ReadFromStream(FS); finally FS.Free; end; end;
procedure TBitVektor.ReadFromStream(AStream: TStream); var FileMagic: AnsiString; NewCapacity: Integer; begin SetLength(FileMagic,4); AStream.Read(PAnsiChar(FileMagic)^,4); if (FileMagic = MAGIC) then begin AStream.Read(NewCapacity,4); SetCapacity(NewCapacity); AStream.Read(FData[0],Length(FData)*4); end else raise Exception.Create('Format-Fehler!'); end;
procedure TBitVektor.SaveToFile(const AFileName: String); var FS: TFileStream; begin FS := TFileStream.Create(AFileName,fmCreate); try WriteToStream(FS); finally FS.Free; end; end;
procedure TBitVektor.SetBit(const AIndex: Integer; const Value: Boolean); begin if Value then FData[AIndex shr 5] := FData[AIndex shr 5] or (1 shl (AIndex and 31)) else FData[AIndex shr 5] := FData[AIndex shr 5] and NOT (1 shl (AIndex and 31)); end;
procedure TBitVektor.SetCapacity(const Value: Integer); begin if (Value > 0) then begin FCapacity := Value; SetLength(FData,((FCapacity +31) shr 5)); end else raise Exception.Create('TBitVektor.Capacity muss >0 sein!'); end;
procedure TBitVektor.WriteToStream(AStream: TStream); begin AStream.Write('NBVF',4); AStream.Write(FCapacity,4); AStream.Write(FData[0],Length(FData)*4); end;
end. |
Benutzung im Demo-Projekt.
cu
Narses
P@u1 - Do 15.04.10 20:12
Wie das grundsätzlich mit den Systemen funktioniert wusste ich schon, ich hatte mich nur gefragt, ob 32 bit 32er system und 64 bit 64er system bedeutet.
64er system finde ich nur komisch, weil dafür die buchstaben nicht ausreichen.
ich habe jetzt vorerst die datei nochmal mit den 0en und 1en als txt gelassen, ist dann rund 26 MB groß.
Mit der Datei wollte ich dann ein paar tests machen.
Wenn ich die Datei in eine Stringlist reinlade, dann ist das komischer weise sofort fertig (kann es sein, dass das dann nicht "wirklich" reingeladen wird, sondern nur die stringlist sich abspeichert, von wo er die infos holen soll oder so?
Und wenn ich das dann in ein Array of Boolean reinladen will dauert das sehr lange.
Ich hab testweise erstmal 10000 array werte reingeladen (von ca. 26 Millionen) und das hat schon über eine sekunde gedauert.
Kann man das nicht irgendwie schneller machen bzw. wieso dauert das überhaupt so lange?
Xentar - Do 15.04.10 20:21
Du könntest uns mal zeigen, WIE du die Daten einliest.
Narses - Do 15.04.10 20:22
Moin!
P@u1 hat folgendes geschrieben : |
| ich habe jetzt vorerst die datei nochmal mit den 0en und 1en als txt gelassen, ist dann rund 26 MB groß. |
Die Klasse oben macht das mit ca. 3MB und in kaum messbarer Zeit. :D Dafür ist der Zugriff auf einzelne Bits halt nicht so schnell, aber man kann eben nicht alles haben. :nixweiss: Ist für wenig Zugriffe und schnellen I/O gemacht.
cu
Narses
P@u1 - Do 15.04.10 20:29
@narses: ich bin leider noch nicht dazu gekommen, mir die klasse anzugucken, werde ich aber später/morgen noch machen.
Und ich muss darauf sehr oft zugreifen, also ist das wahrscheinlich nicht so besonders gut geeignet.
Jetzt dauert es komischerweise nicht mehr lange, sondern gibt eine zugriffsverletzung
wie ich es einlese:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29:
| var Form1: TForm1; b: Array[1..25000000] of Boolean;
procedure TForm1.Button2Click(Sender: TObject); var sl: TStringList; i: Longint; begin sl:=TStringList.Create; sl.LoadFromFile(OpenDialog1.FileName); for i := 1 to 20000000 do begin try if sl[0][i]='1' then b[i]:=true else b[i]:=false; except
ShowMessage(inttostr(i)); sl.free; exit;
end; end; sl.Free;
end; |
die try/except sachen hab ich eingefügt um rauszufinden, bei welchem wert der fehler kommt, er kommt bei i=1566105
ist da vielleicht der integer zuende oder so? (hab jetzt extra integer durch longint ersetzt)
Narses - Do 15.04.10 20:41
Moin!
P@u1 hat folgendes geschrieben : |
| Und ich muss darauf sehr oft zugreifen, also ist das wahrscheinlich nicht so besonders gut geeignet. |
OK, dann nagel doch einfach gleich das Array auf die Platte. :nixweiss:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| var b: Array[0..25000000] of Boolean; FS: TFileStream;
FS.Write(b[0],Length(b)*SizeOf(Boolean));
FS.Read(b[0],Length(b)*SizeOf(Boolean)); |
Ist nicht sparsam mit dem Plattenplatz, aber schnell und einfach. :idea:
cu
Narses
//EDIT: Array-Basis auf 0 gesetzt
P@u1 - Do 15.04.10 20:45
Vielen Dank für eure Hilfe!
Ich hab leider keine Ahnung von FileStreams und ich glaube das bei dem code den du gerade geschrieben hast noch was fehlt, es wird ja nirgendwo was aus einer datei geladen.
Und wieso greifst du auf b[0] zu, obwohl b bei 1 anfängt?
ich versteh das nicht^^
Kannst du bitte nochmal kurz erläutern wie das mit dem filestream funktioniert?
danke!
Narses - Do 15.04.10 20:51
Moin!
P@u1 hat folgendes geschrieben : |
| Ich hab leider keine Ahnung von FileStreams |
Das ist natürlich... :? schlecht... :|
P@u1 hat folgendes geschrieben : |
| und ich glaube das bei dem code den du gerade geschrieben hast noch was fehlt, es wird ja nirgendwo was aus einer datei geladen. |
Klar wird da was geladen, du musst halt noch den FileStream anlegen, der Teil fehlt, das ist richtig (1 Zeile +Resourcen-Schutzblock; Vorlage in der Klasse weiter oben).
P@u1 hat folgendes geschrieben : |
Und wieso greifst du auf b[0] zu, obwohl b bei 1 anfängt?
ich versteh das nicht^^ |
Oh, glatt übersehen. :oops: Habe ich auf 0-basiert umgestellt (solltest du auch tun, dynamische Arrays fangen eh immer bei 0 an, dann spart man sich die Index-Transformation in der Compiler-Magic).
P@u1 hat folgendes geschrieben : |
Kannst du bitte nochmal kurz erläutern wie das mit dem filestream funktioniert?
danke! |
TFILESTREAM :lupe: :les: :think: Sorry, aber das haben wir nun wirklich oft genug hier durchgehechelt... :nixweiss:
Wenn ich´s mir recht überlege, bleib lieber bei deiner Stringliste und warte etwas, das ist insgesamt einfacher. :?
cu
Narses
jfheins - Do 15.04.10 20:53
Narses hat folgendes geschrieben : |
| OK, dann nagel doch einfach gleich das Array auf die Platte. :nixweiss: |
Das ist ihm doch zu voluminös ;)
P@u1 - Do 15.04.10 21:21
danke für eure hilfe, ich habs inzwischen mit dem filestream prinzipiell hingekriegt, schnelligkeit, dateigröße usw. muss ich noch testen
Edit: es gibt wieder ein problem, ein array of boolean kann wohl nur die maximale länge
Array[1..1033337] of Boolean;
haben, wenn ich die 1033337 um nur 1 erhöhe kommt sofort stack overflow
woran kann das liegen, wie kann ich das ändern?
Edit: Derzeitiger Quelltext:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
| procedure TForm1.Button1Click(Sender: TObject); var myArray: Array[1..1033336] of Boolean; MyStream: TFileStream; i: integer; begin randomize; for i := 1 to 103336 do begin if random(2)=1 then myArray[i]:=true else myArray[i]:=false; end;
MyStream:=TFileStream.Create('.\MeineDatei.txt', fmCreate); MyStream.Write(MyArray,SizeOf(MyArray)); myStream.Free; end; |
Hidden - Do 15.04.10 21:48
Hi :)
Der Stack hat nur eine vordefinierte, fixe Größe. Die kannst du aber einstellen.
Wenn du solch ein Array gerade zum ersten Mal anlegst: Wie hast du die Daten denn bisher vorliegen gehabt? Vielleicht ergibt sich ja daraus eine schöne Möglichkeit.
Müssen eigentlich immer alle geladen werden, oder brauchst du stets nur einzelne, kleine Teile?
lg,
P@u1 - Do 15.04.10 21:52
wie vorher schonmal geschrieben, ich habe die daten noch nicht erstellt, weil ich erst gucken wollte in welchem format die am besten sind, ich kann die daten z.B. als array of boolean erstellen.
im späteren einsatz werden immer nur einzelne boolean werte gebraucht, aber relativ häufig.
Edit: Die stack größe steht in den optionen auf $00100000
auf welchen wert sollte ich ihn setzen?
Boldar - Do 15.04.10 22:02
Irgendwie klingt das so, als könnte man das gesamte Konzept noch verbessern.
Was genau macht denn dein programm?
P@u1 - Do 15.04.10 22:20
Also es geht darum wahrscheinlichkeiten/strategien beim poker auszurechnen.
Dazu habe ich gelesen, dass es 2 gute Möglichkeiten gibt:
1. Man macht eine Simulation mit einer begrenzten Anzahl an Zufallswerten
2. Man geht alle (wirklich alle) Möglichkeiten durch
Ich will alle Möglichkeiten durchgehen :D
Nehmen wir an man spielt 1 gegen 1 und man ist beim flop dran (man hat selbst 2 karten (bekannt), der gegner hat 2 karten (unbekannt) und 3 gemeinschaftskarten liegen in der mitte (bekannt).
Also sind noch 4 Karten unbekannt: Der Turn, der River und die zwei Karten des Gegners.
Nun kann man systematisch alle Möglichkeiten durchgehen und gucken, bei wievielen man davon verliert/gewinnt.
Das kann allerdings ein paar Sekunden oder so dauern, fände es besser wenn es schneller/sofort geht.
Deshalb dachte ich ,gehe ich das einmal (wird wahrscheinlich sehr sehr lange dauern) für jede der 25989600 Möglichen Anfangskombinationen (52 über 2) * (50 über 3) durch und bestimme jeweils die Wahrscheinlichkeiten auf Gewinn/Verlust.
Danach wollte ich dann die Ergebnisse abspeichern, zunächst erstmal vereinfacht nur mit Wahrheitswerten, ob die Wahrscheinlichkeit auf Gewinn über oder unter 50% ist.
Dann kann man später die Datei laden, gibt an welche Anfangskombination vorliegt und das Programm sagt einem, ob die Chancen über/unter 50% liegen.
Das soll dann später noch was ausgebaut werden, aber erstmal so zum Konzept^^
Wenn ihr bessere Möglichkeiten seht, bitte her damit, glaube meine ist relativ schlecht :D Evtl wäre es einfach besser einfach die Möglichkeit von oben (ohne Abgleich mit Datei zu optimieren).
Ich wollte erstmal mit der Speicherung der Datei anfangen.
Edit: wenn ich mir das gerade nochmal so durchlese kommt mir das irgendwie lächerlich vor :D 25989600 Möglichkeiten durchzugehen wird wahrscheinlich Jahre (wirklich Jahre) dauern, wenn die Einzelfallbestimmung schon mehrere Sekunden dauert, ich muss mir wohl nen neues Konzept ausdenken
Narses - Do 15.04.10 22:22
Moin!
P@u1 hat folgendes geschrieben : |
Edit: Die stack größe steht in den optionen auf $00100000
auf welchen wert sollte ich ihn setzen? |
Lass die Finger vom Stack und nimm endlich ein dynamisches Array, das liegt auf dem Heap, da ist genug Platz. Dein (lokales) statisches Array passt nicht auf den Stack, das ist der Grund für den Fehler. :idea:
cu
Narses
//EDIT:
P@u1 hat folgendes geschrieben : |
| ich muss mir wohl nen neues Konzept ausdenken |
Jup, das würde ich auch sagen.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!