Unkomprimierte ZIP-Datei

Rund um die LCL und andere Komponenten
Antworten
LazProgger
Beiträge: 63
Registriert: Di 11. Mär 2014, 00:33

Unkomprimierte ZIP-Datei

Beitrag von LazProgger »

Hallo,

ich möchte einige Dateien unkomprimiert in ein ZIP-Archiv packen.

Dazu habe ich folgenden Code entwickelt:

Code: Alles auswählen

 
uses zipper, zstream;
 
procedure TForm1.Button5Click(Sender: TObject);
var
  AZipper: TZipper;
begin
 
  AZipper := TZipper.Create;
  AZipper.Filename := UTF8toSys('ziptest.zip');
 
  try
    AZipper.Entries.AddFileEntry('ziptest1.txt');
    AZipper.Entries.AddFileEntry('ziptest2.txt');
 
    AZipper.Entries[0].CompressionLevel := clnone;
    AZipper.Entries[1].CompressionLevel := clnone;
 
    AZipper.ZipAllFiles;
  finally
    AZipper.Free;
  end;
 
end;  
 
 
Das Problem: Das setzen der Eigenschat "CompressionLevel" scheint keine Wirkung zu haben... Egal was ich da angebe, die Datei wird immer komprimiert...

Mache ich da etwas falsch? Oder gibt es eine andere Möglichkeit, eine unkomprimierte ZIP-Datei anzulegen?

Vielen Dank :)

Komoluna
Beiträge: 565
Registriert: So 26. Aug 2012, 09:03
OS, Lazarus, FPC: Windows(10), Linux(Arch)
CPU-Target: 64Bit

Re: Unkomprimierte ZIP-Datei

Beitrag von Komoluna »

Mit Zips kenn ich mich zwar nicht aus, aber
clNone ist auch eine Farbkonstante. Bist du sicher, dass das Richtige clNone verwendet wird?

MFG

Komoluna
Programmer: A device to convert coffee into software.

Rekursion: siehe Rekursion.

Mathias
Beiträge: 7219
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Unkomprimierte ZIP-Datei

Beitrag von Mathias »

Schreibe einfach:

Code: Alles auswählen

 AZipper.Entries[0].CompressionLevel := zstream.clnone;
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

LazProgger
Beiträge: 63
Registriert: Di 11. Mär 2014, 00:33

Re: Unkomprimierte ZIP-Datei

Beitrag von LazProgger »

Am clNone liegt es nicht, das wäre auch zu einfach gewesen.. clNone ist vom Typ Tcompressionlevel und wird vom Compiler als 0 übersetzt, das stimmt alles.

Ich habe mir das erzeugte ZIP-File jetzt einmal in einem HEX-Editor angesehen und mit einem von 7-Zip erstellten File verglichen.

Die gute Nachricht: Das gewählte Kompressionslevel hat eine Auswirkung, es werden jeweils andere Dateien erzeugt.

Die schlechte Nachricht: Das erzeugte ZIP-Archiv scheint hier nicht der ZIP-Spezifikation zu folgen.

Die von 7-Zip erzeugte Datei ist ab Byte 30 so aufgebaut, dass der Dateiname gefolgt von den Bytes der Datei kommt.

Die von TZipper erzeugte Datei hat auch ab Byte 30 den Dateinamen, danach kommen aber die Bytes 01 27 00 D8 FF und dann erst die unkomprimierte Datei. Also sowohl der Stream des Dateinamen als auch die Datei selber wird richtig in die Datei geschrieben (scheint mir so, ich bin kein Profi), aber diese 5 Bytes sollten da nicht hingehören.. Und die führen anscheinend auch dazu, dass die Datei dann nicht vernünftig gelesen werden kann und 7-Zip anzeigt, die Datei wäre Deflate-komprimiert, was sie aber eigentlich nicht ist.

Eventuell ist das ein Bug vom TZipper? Ich nehme an (nur eine Vermutung), dass diese Bytes so eine Art Dateiheader sind, der aber nur gesetzt wird, falls die Datei auch komprimiert ist und man müsste den TZipper irgendwie dazu bekommen, diese Bytes wegzulassen sofern das Level auf clNone (beziehungsweise 0) steht.... Aber wie?

Michl
Beiträge: 2513
Registriert: Di 19. Jun 2012, 12:54

Re: Unkomprimierte ZIP-Datei

Beitrag von Michl »

Folgendes

Code: Alles auswählen

procedure TForm1.Button1Click(Sender: TObject);
var
  Zip: TZipper;
begin
  Zip := TZipper.Create;
  try
    Zip.Entries.AddFileEntry('Test\test.txt', 'Test\test.txt');
    Zip.Entries.AddFileEntry('Test\test2.txt', 'Test\test2.txt');
    Zip.Entries[0].CompressionLevel := Tcompressionlevel.clmax;
    Zip.Entries[1].CompressionLevel := Tcompressionlevel.clnone;
    if Zip.Entries.Count > 0 then
      Zip.SaveToFile('test.zip');
  except
    on e: Exception do
      ShowMessage(e.Message);
  end;
  FreeAndNil(Zip);
end;
liefert mir ein Zip, was im TotalCommander als Eigenschaft der zweiten Datei eine ungepackte Datei anzeigt - also alles, wie gewünscht.

Ich habe die Zipdatei mal angehangen, kannst ja mal schauen, ob 7Zip die zweite Datei auch als komprimiert betrachtet?!
Dateianhänge
test.zip
(2.48 KiB) 100-mal heruntergeladen

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;  

LazProgger
Beiträge: 63
Registriert: Di 11. Mär 2014, 00:33

Re: Unkomprimierte ZIP-Datei

Beitrag von LazProgger »

Danke für den Test, Michl. Deine angehängte Datei ist interessanterweise korrekt. Sie wird in 7-Zip richtig angezeigt und hat auch nicht die Extra-Bytes zwischen dem Dateinamen und den Daten.

Allerdings bekomme ich leider deinen Code nicht ausgeführt. Es kommt immer der Fehler >Unable to Create File ""< beim Aufruf von .SaveToFile und ich weiß nicht wieso...

Ich hänge mal die ZIP an, die ich mit meinem Code aus dem ersten Post erzeugt habe.. Wäre interessant ob der Total-Commander die auch falsch anzeigt bzw nicht erkennt dass keine Kompression besteht und ob bei dir der Code eventuell auch zu einer richtigen ZIP führt...
Dateianhänge
ziptest.zip
(264 Bytes) 89-mal heruntergeladen

LazProgger
Beiträge: 63
Registriert: Di 11. Mär 2014, 00:33

Re: Unkomprimierte ZIP-Datei

Beitrag von LazProgger »

Den Grund für den Unable to Create File "" - Fehler habe ich jetzt gefunden.

Im TZipper existiert folgender Code (Zeile 1461):

Code: Alles auswählen

 
procedure TZipper.SaveToFile(AFileName: string);
var
  lStream: TFileStream;
begin
  lStream:=TFileStream.Create(FFileName,fmCreate);
  try
    SaveToStream(lStream);
  finally
    FreeAndNil(lStream);
  end;
end;   
 
 
Also oben AFileName vs unten FFilename. Und FFileName ist dann natürlich leer...

Ich habe das korrigiert und den Code ausgeführt, die Datei test.zip wurde erstellt hat aber genau den selben Fehler. In 7-Zip wird die Datei als komprimiert angezeigt, im HEX-Editor sind die Bytes wieder da.

Benutzen wir die gleiche Lazarus Version? Ich benutze 1.4.2...
Dateianhänge
test.zip
(2.49 KiB) 98-mal heruntergeladen

LazProgger
Beiträge: 63
Registriert: Di 11. Mär 2014, 00:33

Re: Unkomprimierte ZIP-Datei

Beitrag von LazProgger »

Und noch einmal ich...

Ich habe gerade mal in den aktuellen Snapshot von FPC 3.1.1 geschaut.

Da wurde die Stelle inzwischen korrigiert:

Code: Alles auswählen

 
procedure TZipper.SaveToFile(AFileName: string);
var
  lStream: TFileStream;
begin
  FFileName:=AFileName;
  lStream:=TFileStream.Create(FFileName,fmCreate);
  try
    SaveToStream(lStream);
  finally
    FreeAndNil(lStream);
  end;
end;
 
Dann benutzt du wohl diese Version?! Vielleicht wurde da ja auch inzwischen das Problem behoben?!

Michl
Beiträge: 2513
Registriert: Di 19. Jun 2012, 12:54

Re: Unkomprimierte ZIP-Datei

Beitrag von Michl »

Aktuell nutze ich zur Entwicklung tatsächlich FPC 3.1.1. Außerdem habe ich das Projekt auch einmal mit Lazarus 1.4.2 (FPC 2.6.4) gestartet und kann den von dir festgestellten Fehler dort nachvollziehen.

Ich habe mir mal die DIFFs von PASZLIB angesehen. Die mMn entscheidende Änderung dazu wurde schon im September 2012 vorgenommen, aber erst in 2.7.1 eingepflegt, ist daher nicht in 2.6.4 drin.

PS: Seit Sept. 2013 werden im Trunc auch 64bit unterstützt (was bei mir auch soweit funktioniert - hatte mir in den letzten Tagen ein Programm geschrieben, was Dateien/Verzeichnisse packt und verschlüsselt).

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;  

LazProgger
Beiträge: 63
Registriert: Di 11. Mär 2014, 00:33

Re: Unkomprimierte ZIP-Datei

Beitrag von LazProgger »

Das würde natürlich einiges erklären...

Meinst du ich kann jetzt einfach die zipper Unit aus dem Trunc kopieren und mit meiner 2.6.4 Version verwenden statt der dortigen unit?

Michl
Beiträge: 2513
Registriert: Di 19. Jun 2012, 12:54

Re: Unkomprimierte ZIP-Datei

Beitrag von Michl »

LazProgger hat geschrieben:Meinst du ich kann jetzt einfach die zipper Unit aus dem Trunc kopieren und mit meiner 2.6.4 Version verwenden statt der dortigen unit?
Da es ein FPC-Package ist, könnte es funktionieren (falls es nicht Features vom Trunc benötigt), aber wenn dann, nicht nur die Zipper.pp, sondern alle benötigten Dateien vom Package PASZLIB.

[Edit] Habe es eben mal ausprobiert. Ich habe alle Dateien vom FPC-Trunc\packages\paszlib\src in mein Projektverzeichnis kopiert und mit Lazarus 1.4.2 (FPC 2.6.4) gestartet. Bei mir funktioniert es.

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;  

LazProgger
Beiträge: 63
Registriert: Di 11. Mär 2014, 00:33

Re: Unkomprimierte ZIP-Datei

Beitrag von LazProgger »

Perfekt, habs jetzt zum laufen bekommen, indem ich die Dateien übernommen habe.

Vielen Dank!!

Antworten