Delphi-PRAXiS
Seite 2 von 3     12 3      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Ordentliche Komprimierungsunit (https://www.delphipraxis.net/138629-ordentliche-komprimierungsunit.html)

jfheins 16. Aug 2009 11:43

Re: Ordentliche Komprimierungsunit
 
Zitat:

Zitat von alzaimar
Code:
    zc := TCompressionStream.Create(clMax, ms1);
    try
      zc.CopyFrom(ms, 0);
    finally
      [color=#FF0000][b]zc.free;[/b][/color]
    end;
    lRateOfCompression.Caption := Format('%.3f', [[color=#FF0000][b]zc.CompressionRate[/b][/color]]);

Das kann gutgehen ... muss aber nicht :mrgreen:

GreenHorn3600 16. Aug 2009 12:22

Re: Ordentliche Komprimierungsunit
 
Hallo alzaimar,

dank Dir. Ich bin ja auch nur ein GreenHorn. Hab aber noch ein paar fragen dazu. Mein Stream (TStream) kennt kein .Clear wie kann man das dennoch wieder säubern?

Andere Frage, beim Stream schreibst Du
Delphi-Quellcode:
zc.CopyFrom(ms, 0)
Dies ist definiert als:
Delphi-Quellcode:
function TStream.CopyFrom(Source: TStream; Count: Int64): Int64;
...
begin
  if Count = 0 then
  begin
    Source.Position := 0;
    Count := Source.Size;
  end;
Weshalb Funktioniert dann
Delphi-Quellcode:
zc.CopyFrom(ms, ms.size)
nicht?

Dank Euch,
das GreenHorn

SirThornberry 16. Aug 2009 12:38

Re: Ordentliche Komprimierungsunit
 
Wenn clear nicht vorhanden ist kann man auch einfach mit dem Property-Size die Größe auf 0 setzen.
Oder was in den meisten Fällen performanter ist - die Größe gleich auf den richtigen Wert setzen. In diesem Fall also:
Delphi-Quellcode:
procedure CompressStream(ms: TStream);
var
  zc: TCompressionStream;
  ms1: TMemoryStream;
begin
  ms1 := TMemoryStream.Create;
  try
    zc := TCompressionStream.Create(clMax, ms1);
    try
      zc.CopyFrom(ms, 0);
    finally
      zc.free;
    end;
    lRateOfCompression.Caption := Format('%.3f', [zc.CompressionRate]);
    ms.size := ms1.size;
    ms.position := 0;
    ms1.postion := 0;
    ms.CopyFrom(ms1, ms1.size);
  finally
    ms1.free;
  end;
end;
Zitat:

Weshalb Funktioniert dann...nicht?
"Nicht funktionieren" ist eine sehr schlechte Fehlerbeschreibung. Kommt eine Fehlermeldung? Passiert einfach etwas anderes als erwartet? Wenn ja: was erwartest du und was passiert tatsächlich?

GreenHorn3600 16. Aug 2009 13:14

Re: Ordentliche Komprimierungsunit
 
Hallo Wissende,

kann man diesen Code noch optimieren? Geht darum, dass der Stream aStream komprimiert wird und der komprimierte anschliessend wieder im aStream zurückgegeben wird.

Delphi-Quellcode:
procedure CompressStream(aStream: TStream);
var
  zc: TZCompressionStream;
  ms: TMemoryStream;
begin
  ms := TMemoryStream.Create;
  try
   zc := TZCompressionStream.Create(ms, zcMax);
   try
      zc.CopyFrom(aStream, 0);
    finally
      zc.Free;
    end;
    aStream.Size := 0;
    aStream.copyFrom(ms, 0);
  finally
    ms.Free;
end;
@SirThornberry: beim aStream.copyfrom(ms, ms.size), sass wohl das Problem vor dem Bildschirm. Danke.

Greeny

Klaus01 16. Aug 2009 13:29

Re: Ordentliche Komprimierungsunit
 
Vielleicht geht es so schneller?

Delphi-Quellcode:
procedure CompressStream(aStream: TStream);
var
  zc: TZCompressionStream;
  ms: TStream;
begin
  ms := (ms as TMemoryStream).Create;
  zc := TZCompressionStream.Create(ms, zcMax);
  try
    zc.CopyFrom(aStream, 0);
  finally
    zc.Free;
  end;
  aStream.Free
  aStream:=ms;
 end;
Grüße
Klaus

mirage228 16. Aug 2009 13:53

Re: Ordentliche Komprimierungsunit
 
Als Alternative zur ZLIB würde ich gerne noch Bei Google suchenTurboPower Abbrevia in den Raum werfen. Kommt sogar ohne DLL aus und kann neben ZIP auch CAB Archive verarbeiten :)

jfheins 16. Aug 2009 14:02

Re: Ordentliche Komprimierungsunit
 
Zitat:

Zitat von Klaus01
Vielleicht geht es so schneller?

Delphi-Quellcode:
procedure CompressStream(aStream: TStream);
var
  zc: TZCompressionStream;
  ms: TStream;
begin
  ms := (ms as TMemoryStream).Create;
  zc := TZCompressionStream.Create(ms, zcMax);
  try
    zc.CopyFrom(aStream, 0);
  finally
    zc.Free;
  end;
  aStream.Free
  aStream:=ms;
 end;
Grüße
Klaus

2 Fehler fallen sogar mir sofort auf:

1. ms := (ms as TMemoryStream).Create; sollte ne Exception werfen, wenn dann so:
ms := TMemoryStream.Create;

2. astream müsste als var Parameter deklariert werden. So wird der übergebene Stream freiegegeben, und der lokale nicht.

Zur Logik: Ich darf nen beliebigen Stream reinpacken, und der wird hinterrücks freigeben und durch einen Memorystream ersetzt. Als hätte der Autor überlegt "Hmmm ... wie könnte ich das programmieren, damit der Zweck zwar erfüllt wird, aber die Funktion trotzdem möglichst unerwartet reagiert?"

Klaus01 16. Aug 2009 14:20

Re: Ordentliche Komprimierungsunit
 
Zitat:

Zitat von jfheins
2. astream müsste als var Parameter deklariert werden. So wird der übergebene Stream freiegegeben, und der lokale nicht.

Meine Absicht war, dass der übergebene Stream freigegeben wird und anschließend die
Adresse des intern erzeugten Streams zugewiesen bekommt.
So könnte das unkopieren entfallen.

Im Punkt 1 gebe ich Dir recht.

Objekte die als Paramter einer Routine übergeben werden müßen nicht als
var gekennzeichnet werden damit Änderungen auch ausserhalb der Routine
wahrgenommen werden.

Grüße
Klaus

jfheins 16. Aug 2009 15:02

Re: Ordentliche Komprimierungsunit
 
Wenn man ein Objekt an eine Funktion "normal" übergibt, geschieht dies mit call-by-value. Es wird also der Zeiger, der auf das Objekt zeigt kopiert und der Funktion gegeben.

Alles was im Objekt ist, wird natürlich nicht kopiert und Änderungen wirken sich auf den Aufrufer aus.

Der Zeiger selbst wird aber immernoch kopiert - d.h. es gibt 2 Zeiger (einen beim Aufrufer und einen in der Funktion). Wenn du also auf deiesen Zeiger ein aValue.Free() ausführst wird das Orginal-Objekt zerstört.
Jetzt sagst du:
aValue := ms;
damit wird der lokalen Kopie des Zeigers die Adresse des internen Streams zugewiesen. Der äußere Zeiger bleibt unverändert. Beim Verlassen der Funktion wird der Zeiger dann auch weggeworfen.

Wer auch immer diese Funktion aufruft, hat danach einen ungültigen Zeiger und ein Speicherleck :stupid:

Der var-Parameter würde dafür sogen, dass der Zeiger nicht kopiert wird, sondern sozusagen ein Zeiger auf den Zeiger übergeben wird. Dann kannst du auch den Orginal-Zeiger ändern.

Gut ist das alles abder trotzdem nicht (weshalb sich diese Frage beim normalen Programmieren auch nicht stellt :P ). Stell dir vor, du öffnest eine Datei und willst die komprimieren. Du übergibt also nen Filestream und bekommt ... einen Memorystream zurück, in dem die komprimierte Datei steht. Der Filestream wurde freigegeben. Tolle Logik :mrgreen:

GreenHorn3600 17. Aug 2009 23:15

Re: Ordentliche Komprimierungsunit
 
Halo Mirage,

danke für den Tipp, aber das ganze sollte schon mit Bordmitteln funktionieren, oder zumindest für OS und kommerzielle Programme (kostenlos) einsetzbar sein. Und da gibt es dann halt nicht mehr viel :-(

Gut, die ZLib, komprimiert jetzt mal, aber so ordentlich auch nicht. Sie schafft da Grad mal 1,44%, aber immerhin...

BTW: @alzaimer: der TZCompress ist der Name aus der unit zLib unter D2.9 unter D2.6 ist das ganze noch ohne Z . Dafür kann er keine Memorystreams. Kennst Du hier vielleicht einen Trick, um ihm Memorystreams beizubringen (in D2.6)?

Grüße
Greeny


Alle Zeitangaben in WEZ +1. Es ist jetzt 06:40 Uhr.
Seite 2 von 3     12 3      

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