![]() |
Klasse mit vielen MemoryStreams (andere Möglichkeit)
So hallo erstmal wieder...
Es geht im Folgendes: Ich arbeite bei meinem Spiel mit der ZLib von JVCL (damit man die Dateien nicht mit jedem Zip programm lesen kann :-D) Das funkt soweit super. Nur wollte ich dies auch für eine gepackte Datei verwenden, die alle Texturen enthält. Packen geht. So nur entpacken geht nur in einen Ordner und dan werden dort die Dateien gespeichert. Was ich dumm finde bei einem Spiel, da es unnötig Speicherplatz wegnihmt (wenn mal viele drin sind dan nochmal entpacket..ist irgendwie unprofessionel) Also dachte ich mir ich schreib mir die Komponente für meine Gebrauch ein wenig um. Die Funktion DecompressFile arbeitet mit TFileStreams zum speichern der entpackten Dateien. Nun wollte ich mit TObjectList eine Klasse machen, die mehrere TMemoryStreams (weil ich keine anderen Stream kenne bei Delphi2009, der Daten in den Speicher läd) aufnihmt. So nun beim erstellen des Streams gehts noch wenn ich jedoch eine TMemoryStream der objektliste hinzufüge, macht er dies nicht. Bekomm ne Zugriefsverletzung. Egal wie ich es Drehte oder wendete er machte es nicht mit mehren TMemoryStreams. Daraufhin hab ich es mit einem array von Bytes gemacht. Funkt nun auch. Ich verwende die vorgegeben Klasse TBytes (ein dynamischer array von Bytes) zum speichern der Daten einer Datei im speicher. Zum Abrufen hab ich eine Prozedur geschrieben die den array von Bytes in einen TMemoryStream kopiert, damit ich dan allgemein damit weiterarbeiten von (nämlich von Streams in meine Engine laden, gibt keine anderen Weg :-D) Nun zu meiner Frage: Ist es klug nur einen Dynamischen Array zuverwenden? Der hat ja ne begrenzte Anzahl. Und in einem Stream kann ich sowieso nur 1024 Bytes mit einmal Write schreiben. Eine Datei kann aber viel größer sein, ich hab dan die befürschtung, das wenn die datei größer ist als ein dynamischer array, die dann nicht gelesen werden kann. Ist es besser einen array der so aussieht zumachen?
Code:
Damit hät ich einen dynamischen array von 1024 Bytes.
Dateiarray : array of array [0..1023] of Byte;
Oder weis wer eine andere elegantere Variante? Und warum bekomm ich bei dem versuch einen TMemoryStream in eine Objektliste hinzufügen eine zugriefsverletzung? (ich hab die TObjectList klasse umgeschrieben, mit inherite usw.) |
AW: Klasse mit vielen MemoryStreams (andere Möglichkeit)
Verfolge den Ansatz mit der TObjectList und TMemoryStream weiter.
Das Hin- und Hergewandel verbraucht doch nur unnötig Performance. Warum da eine Zugriffsverletzung kommt ... Tja da muss ich mich erst mal durch den umfangreichen Code von dir durcharbeiten. :stupid: Warum TObjectList umschreiben? Wenn du zusätzlich zu der Liste mit den MemoryStreams auch noch einen durchsuchbaren Index benötigst, dann würde sich sogar noch eher eine TStringList anbieten ;) Bei Delphi 2010 gibt es dafür auch TDictionary (gibt es das bei D2009 auch schon?) |
AW: Klasse mit vielen MemoryStreams (andere Möglichkeit)
hmm okay also ich poste mal wie ich das gemacht habe. Vllt hilft es ja weiter...
Delphi-Quellcode:
type
TZLibEntpackedStream = class(TMemoryStream) //Da TMemoryStream von TObject bereits abstammt private FFileName : TFileName; public property FileName : TFileName read FFileName write FFileName; end; TStreamList = class(TObjectList) protected function GetItem(Index: Integer): TZLibEntpackedStream; procedure SetItem(Index: Integer; AStream: TZLibEntpackedStream); public function Add(AStream: TZLibEntpackedStream): Integer; function Remove(AStream: TZLibEntpackedStream): Integer; function IndexOf(AStream: TZLibEntpackedStream): Integer; function First: TZLibEntpackedStream; function Last: TZLibEntpackedStream; procedure Insert(Index: Integer; AStream: TZLibEntpackedStream); property Items[Index: Integer]: TZLibEntpackedStream read GetItem write SetItem; default; end; TStreamZlibMultiple = class(TJvZlibMultiple) public procedure DecompressStream(Stream: TStream; var StreamList : TStreamList); overload; end; implementation function TStreamList.GetItem(Index: Integer): TZLibEntpackedStream; begin Result := TZLibEntpackedStream(inherited GetItem(Index)); end; procedure TStreamList.SetItem(Index: Integer; AStream: TZLibEntpackedStream); begin inherited Items[Index] := AStream; end; function TStreamList.Add(AStream: TZLibEntpackedStream) : Integer; begin Result := inherited Add(AStream); end; function TStreamList.Remove(AStream: TZLibEntpackedStream): Integer; begin Result := inherited Remove(AStream); end; function TStreamList.IndexOf(AStream: TZLibEntpackedStream): Integer; begin Result := inherited IndexOf(AStream); end; function TStreamList.First: TZLibEntpackedStream; begin Result := TZLibEntpackedStream(inherited First); end; function TStreamList.Last: TZLibEntpackedStream; begin Result := TZLibEntpackedStream(inherited Last); end; procedure TStreamList.Insert(Index: Integer; AStream: TZLibEntpackedStream); begin inherited Insert(Index,AStream); end; procedure TStreamZlibMultiple.DecompressStream(Stream: TStream; var StreamList : TStreamList); var MemoryStream: TZLibEntpackedStream; ZStream: TJclZLibDecompressStream; CStream: TMemoryStream; B, LastPos: Byte; AnsiS: AnsiString; S: string; Count, FileSize, I: Integer; Buffer: array [0..1023] of Byte; TotalByteCount: Longword; FileStreamSize, StreamSize: Int64; begin if not Assigned(StreamList) then StreamList := TStreamList.Create; StreamSize := Stream.Size; // cache, to not FileSeek on every iteration while Stream.Position < StreamSize do begin //Read and force the directory //Fällt weg weil ich das net brauch muss aber Count gelesen werden Stream.Read(B, SizeOf(B)); S := ''; //Read filename Stream.Read(B, SizeOf(B)); if B > 0 then begin AnsiS := AnsiString(S); LastPos := Length(AnsiS); SetLength(AnsiS, LastPos + B); Stream.Read(AnsiS[LastPos + 1], B); S := string(AnsiS); end; Stream.Read(FileSize, SizeOf(FileSize)); Stream.Read(I, SizeOf(I)); CStream := TMemoryStream.Create; try CStream.CopyFrom(Stream, I); CStream.Position := 0; //Decompress the file //1. Funkt net MemoryStream := StreamList.Items[StreamList.Add(TZLibEntpackedStream.Create)]; //Hier kommt der Fehler MemoryStream.FFileName := S; //2. Funkt net MemoryStream := TZLibEntpackedStream.Create; StreamList.Add(MemoryStream);//Hier kommt der Fehler MemoryStream.FFileName := S; ZStream := TJclZLibDecompressStream.Create(CStream); try TotalByteCount := 0; { (RB) ZStream has an OnProgress event, thus copyfrom can be used } FileStreamSize := 0; repeat Count := ZStream.Read(Buffer, SizeOf(Buffer)); if Assigned(MemoryStream) then begin Inc(FileStreamSize, MemoryStream.Write(Buffer, Count)); DoProgress(FileStreamSize, FileSize); end; Inc(TotalByteCount, Count); until Count = 0; if Assigned(OnDecompressedFile) then OnDecompressedFile(Self, S, TotalByteCount); finally FreeAndNil(MemoryStream); ZStream.Free; end; finally CStream.Free; end; end; end; Für den Original-Code kann man ja selber gugen. Also ich hab keine Ahnung woran das liegt. Aufrufen tuh ich das so:
Delphi-Quellcode:
Stream natürlich initalisiert und auch eine StreamList Variable erstellen xD
TStreamZlibMultiple(JvZlibMultiple1).DecompressStream(Stream,StreamList);
|
AW: Klasse mit vielen MemoryStreams (andere Möglichkeit)
Nimm mal diese Zeile raus
Delphi-Quellcode:
und schau ob die Fehler an den Stellen noch auftreten
if not Assigned(StreamList) then
(ich habe da so einen Verdacht ;) ) |
AW: Klasse mit vielen MemoryStreams (andere Möglichkeit)
Dies hatte ich auch schon veruscht, und hab das Crate und Assigned rausgenohmen und vor DecompressStream nur Create gemacht und auch in DecompressStrema nur Create, funkt alles nichts. Es hängt halt nur an diese stelle.
EDIT:Okay....ehm ja...Es funkt jetzt, hab ne vermutung worans lag, ich hab zum schluss den Stream von der TStreamLisT im DecompressStream-Code freigegeben, ich glaub daran lags. Hab nochmal getestet funk jetzt. Danke Sir Rufo für die Hilfe. Manchmal liegt der Fehler so na und doch so fern xD Hier der fertige Code fals es mal jemand brauch xD
Delphi-Quellcode:
type
TZLibEntpackedStream = class(TMemoryStream) //Da TMemoryStream von TObject bereits abstammt private FFileName : TFileName; public property FileName : TFileName read FFileName write FFileName; end; TStreamList = class(TObjectList) protected function GetItem(Index: Integer): TZLibEntpackedStream; procedure SetItem(Index: Integer; AStream: TZLibEntpackedStream); public function Add(AStream: TZLibEntpackedStream): Integer; function Remove(AStream: TZLibEntpackedStream): Integer; function IndexOf(AStream: TZLibEntpackedStream): Integer; function First: TZLibEntpackedStream; function Last: TZLibEntpackedStream; procedure Insert(Index: Integer; AStream: TZLibEntpackedStream); property Items[Index: Integer]: TZLibEntpackedStream read GetItem write SetItem; default; end; TStreamZlibMultiple = class(TJvZlibMultiple) public procedure DecompressIntoStream(Stream: TStream; var StreamList : TStreamList); end; implementation function TStreamList.GetItem(Index: Integer): TZLibEntpackedStream; begin Result := TZLibEntpackedStream(inherited GetItem(Index)); end; procedure TStreamList.SetItem(Index: Integer; AStream: TZLibEntpackedStream); begin inherited Items[Index] := AStream; end; function TStreamList.Add(AStream: TZLibEntpackedStream) : Integer; begin Result := inherited Add(AStream); end; function TStreamList.Remove(AStream: TZLibEntpackedStream): Integer; begin Result := inherited Remove(AStream); end; function TStreamList.IndexOf(AStream: TZLibEntpackedStream): Integer; begin Result := inherited IndexOf(AStream); end; function TStreamList.First: TZLibEntpackedStream; begin Result := TZLibEntpackedStream(inherited First); end; function TStreamList.Last: TZLibEntpackedStream; begin Result := TZLibEntpackedStream(inherited Last); end; procedure TStreamList.Insert(Index: Integer; AStream: TZLibEntpackedStream); begin inherited Insert(Index,AStream); end; procedure TStreamZlibMultiple.DecompressIntoStream(Stream: TStream; var StreamList : TStreamList); var MemoryStream: TZLibEntpackedStream; ZStream: TJclZLibDecompressStream; CStream: TMemoryStream; B, LastPos: Byte; AnsiS: AnsiString; S: string; Count, FileSize, I: Integer; Buffer: array [0..1023] of Byte; TotalByteCount: Longword; FileStreamSize, StreamSize: Int64; begin StreamList := TStreamList.Create; StreamSize := Stream.Size; // cache, to not FileSeek on every iteration while Stream.Position < StreamSize do begin //Read and force the directory //Fällt weg weil ich das net brauch muss aber Count gelesen werden Stream.Read(B, SizeOf(B)); S := ''; //Read filename Stream.Read(B, SizeOf(B)); if B > 0 then begin AnsiS := AnsiString(S); LastPos := Length(AnsiS); SetLength(AnsiS, LastPos + B); Stream.Read(AnsiS[LastPos + 1], B); S := string(AnsiS); end; Stream.Read(FileSize, SizeOf(FileSize)); Stream.Read(I, SizeOf(I)); CStream := TMemoryStream.Create; try CStream.CopyFrom(Stream, I); CStream.Position := 0; //Decompress the file MemoryStream := TZLibEntpackedStream.Create; StreamList.Add(MemoryStream); MemoryStream.FFileName := S; ZStream := TJclZLibDecompressStream.Create(CStream); try TotalByteCount := 0; { (RB) ZStream has an OnProgress event, thus copyfrom can be used } FileStreamSize := 0; repeat Count := ZStream.Read(Buffer, SizeOf(Buffer)); if Assigned(MemoryStream) then begin Inc(FileStreamSize, MemoryStream.Write(Buffer, Count)); DoProgress(FileStreamSize, FileSize); end; Inc(TotalByteCount, Count); until Count = 0; if Assigned(OnDecompressedFile) then OnDecompressedFile(Self, S, TotalByteCount); finally ZStream.Free; end; finally CStream.Free; end; end; end; |
AW: Klasse mit vielen MemoryStreams (andere Möglichkeit)
Das Erzeugen der Streamlist sollte dort erfolgen, wo diese auch wieder freigegeben wird.
Dann kann diese auch als einfacher Parameter übergeben werden (kein var-Parameter).
Code:
In der Funktion DecompressIntoStream am Anfang eventuell StreamList.Clear aufrufen.
StreamList := TStreamList.Create;
try DecompressIntoStream(Stream, StreamList); {... weiter Verwendung von StreamList} finally StreamList.Free; end; |
AW: Klasse mit vielen MemoryStreams (andere Möglichkeit)
Schlussendlich läuft es darauf hinaus, dass du lediglich ein Container-Format benötigst. In diesem Zusammenhang kann ich ohne Einschränkungen folgende Klasse empfehlen:
![]() On-the-fly Komprimierung/Verschlüsselung ist ebenfalls möglich. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 02:40 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