AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Algorithmen, Datenstrukturen und Klassendesign Delphi Klasse mit vielen MemoryStreams (andere Möglichkeit)
Thema durchsuchen
Ansicht
Themen-Optionen

Klasse mit vielen MemoryStreams (andere Möglichkeit)

Ein Thema von NickelM · begonnen am 2. Jan 2011 · letzter Beitrag vom 4. Jan 2011
Antwort Antwort
NickelM

Registriert seit: 22. Jul 2007
Ort: Carlsberg
445 Beiträge
 
Delphi 2009 Professional
 
#1

Klasse mit vielen MemoryStreams (andere Möglichkeit)

  Alt 2. Jan 2011, 09:36
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 )
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 )
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:
Dateiarray : array of array [0..1023] of Byte;
Damit hät ich einen dynamischen array von 1024 Bytes.
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.)
Nickel
"Lebe und denke nicht an morgen"
Zitat aus dem gleichnamigen Bollywoodfilm.
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#2

AW: Klasse mit vielen MemoryStreams (andere Möglichkeit)

  Alt 2. Jan 2011, 09:58
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.

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?)
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)

Geändert von Sir Rufo ( 2. Jan 2011 um 10:05 Uhr)
  Mit Zitat antworten Zitat
NickelM

Registriert seit: 22. Jul 2007
Ort: Carlsberg
445 Beiträge
 
Delphi 2009 Professional
 
#3

AW: Klasse mit vielen MemoryStreams (andere Möglichkeit)

  Alt 2. Jan 2011, 12:48
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:
TStreamZlibMultiple(JvZlibMultiple1).DecompressStream(Stream,StreamList); Stream natürlich initalisiert und auch eine StreamList Variable erstellen xD
Nickel
"Lebe und denke nicht an morgen"
Zitat aus dem gleichnamigen Bollywoodfilm.
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#4

AW: Klasse mit vielen MemoryStreams (andere Möglichkeit)

  Alt 2. Jan 2011, 22:38
Nimm mal diese Zeile raus
if not Assigned(StreamList) then und schau ob die Fehler an den Stellen noch auftreten

(ich habe da so einen Verdacht )
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
NickelM

Registriert seit: 22. Jul 2007
Ort: Carlsberg
445 Beiträge
 
Delphi 2009 Professional
 
#5

AW: Klasse mit vielen MemoryStreams (andere Möglichkeit)

  Alt 4. Jan 2011, 06:18
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;
Nickel
"Lebe und denke nicht an morgen"
Zitat aus dem gleichnamigen Bollywoodfilm.

Geändert von NickelM ( 4. Jan 2011 um 06:44 Uhr)
  Mit Zitat antworten Zitat
Blup

Registriert seit: 7. Aug 2008
Ort: Brandenburg
1.429 Beiträge
 
Delphi 10.4 Sydney
 
#6

AW: Klasse mit vielen MemoryStreams (andere Möglichkeit)

  Alt 4. Jan 2011, 10:27
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:
StreamList := TStreamList.Create;
try
  DecompressIntoStream(Stream, StreamList);

  {... weiter Verwendung von StreamList}

finally
  StreamList.Free;
end;
In der Funktion DecompressIntoStream am Anfang eventuell StreamList.Clear aufrufen.
  Mit Zitat antworten Zitat
WladiD

Registriert seit: 27. Jan 2006
Ort: Celle
135 Beiträge
 
Delphi 10.4 Sydney
 
#7

AW: Klasse mit vielen MemoryStreams (andere Möglichkeit)

  Alt 4. Jan 2011, 10:56
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:

Big Table 1.12 von Arnaud Bouchez (Er ist ein echter Delphi-Crack)

On-the-fly Komprimierung/Verschlüsselung ist ebenfalls möglich.
Waldemar Derr
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 15:36 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