Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   TZipFile (https://www.delphipraxis.net/209421-tzipfile.html)

Willie1 3. Dez 2021 17:19

TZipFile
 
Hallo, jetzt zu meiner Frage.
Ich packe ca. 80 Dateien jede 2939 oder2777 Bytes groß in ein Zip-Archiv. Nicht um Platz zu sparen, sondern mit nur einer Datei umgehen zu können. Ich benutze TZipFile. Das auspacken klappt, mit dem Packen gibt es ein Problem. Mit TZipFile.Add lässt sich keine Datei im Archiv überschreiben. (Habe ich hier gelernt) Deshalb habe ich mir selbst was ausgedacht, wahrscheinlich umständlich aber ich kann es nicht besser. Das funktioniert auch und das Archiv lässt sich mit TZipFile wieder auspacken auch mit dem Windows-Explorer und WinRar. Nur ist mir erst jetzt nach 6 Mon. aufgefallen, dass mein Zip riesig groß wird, größer als das Original. Was ist da los?
Quellcode kann ich hochladen.
Willie

Nebenbei: Das Szenario von gestern wiederholt sich. Wenn ich Vorschau anklicke, muss ich mich wieder anmelden Diesmal hat die Rückwärtstaste geholfen. Die Vorschau geht nicht.

TurboMagic 3. Dez 2021 17:53

AW: TZipFile
 
Hallo,

wenn du uns nicht sagst, was du dir ausgedacht hast, können wir's auch nicht beurteilen/verbessern. ;-)

Grüße
TurboMagic

himitsu 3. Dez 2021 20:50

AW: TZipFile
 
Die etwas Delphi-Implementation kann nur anhängen, aber nichts nachträglich ändern/überschreiben/löschen.

Du müsstest also die Datei kopieren, also lesend von einer ZIP, schreibend in eine Neue, und beim Kopieren deine Änderungen vornehmen.



Wenn die Dateigröße egal ist, dann einfach die Datei nochmal anhängen (mit dem gleichen Dateinamen) und beim entpacken überschreiben lassen, bzw. jeweils die letzte Version auslesen.

Willie1 4. Dez 2021 10:45

AW: TZipFile
 
Delphi-Quellcode:
procedure TWZZipFile.AddandOverride(const aFilename: string; const ArchiveFileName: string);
var
  TempPa, TempName: string;
  List: TStringDynArray;
  i: Integer;
  Done: Boolean;
begin
  if TFileAttribute.faReadOnly in TFile.GetAttributes(ArchiveFilename, false) then begin
    ShowMessage('Archiv "'+ExtractFilename(ArchiveFilename)+'"ist schreibgeschützt!');
    Exit;
  end;
  Done := false;
  if IsValid(ArchiveFilename) then begin
//    TempPa := TPath.GetTempPath+Format('~~~%.4x',[Random($FFFF)]);
    TempPa := TPath.Combine(TPath.GetTempPath, TPath.GetRandomFileName);
    TDirectory.CreateDirectory(TempPa);
    Open(ArchiveFilename, zmRead);
    ExtractAll(TempPa);
    if CopyFile(PWideChar(aFilename), PWideChar(TPath.Combine(TempPa, ExtractFilename(aFilename))), false) then
    begin
      List := TDirectory.GetFiles(TempPa);
      TempName := ExtractFilePath(ArchiveFilename) + ExtractFilename(TPath.GetTempFileName);
      Open(TempName, zmWrite);
      for i := Low(List) to High(List) do begin
        Add(List[i]);
        TFile.Delete(List[i]);
      end;
      Close;
      Done := true;
    end;
    Close;
  end;
  if Done then begin
    TFile.Delete(ArchiveFilename);
    if RenameFile(TempName, ArchiveFilename) then
      TDirectory.Delete(TempPa, true);
  end;
end;

procedure TWZZipFile.AddandOverride(const aFileNames: TStrings; const ArchiveFileName: string);
var
  TempPa, TempName: string;
  List: TStringDynArray;
  i: Integer;
  Done: Boolean;
begin
  if TFileAttribute.faReadOnly in TFile.GetAttributes(ArchiveFilename, false) then begin
    ShowMessage('Archiv "'+ExtractFilename(ArchiveFilename)+'"ist schreibgeschützt!');
    Exit;
  end;
  Done := false;
  if IsValid(ArchiveFilename) then begin
    TempPa := TPath.Combine(TPath.GetTempPath, TPath.GetRandomFileName);
    TDirectory.CreateDirectory(TempPa);
    Open(ArchiveFilename, zmRead);
    ExtractAll(TempPa);
    for i := 0 to aFilenames.Count - 1 do begin
      Done := CopyFile(PWideChar(aFilenames[i]), PWideChar(TPath.Combine(TempPa, ExtractFilename(aFilenames[i]))), false);
      if not Done then Break;
    end;
    if Done then begin
      Done := false;
      List := TDirectory.GetFiles(TempPa);
      TempName := ExtractFilePath(ArchiveFilename) + ExtractFilename(TPath.GetTempFileName);
      Open(TempName, zmWrite);
      for i := Low(List) to High(List) do begin
        Add(List[i]);
        TFile.Delete(List[i]);
      end;
      Close;
      Done := true;
    end;
    Close;
  end;
  if Done then begin
    TFile.Delete(ArchiveFilename);
    if RenameFile(TempName, ArchiveFilename) then
      TDirectory.Delete(TempPa, true);
  end;
end;
  1. Archiv in Temp-Ordner auspacken
  2. Datei(en) dort hinein kopieren und eventuell überschreiben
  3. Neues Archiv mit Add anlegen
  4. Altes Archiv löschen und neues umbebenenn.
So habe ich es mir vorgegetellt. Willie.

Harry Stahl 4. Dez 2021 11:35

AW: TZipFile
 
Zitat:

Zitat von himitsu (Beitrag 1498655)
Die etwas Delphi-Implementation kann nur anhängen, aber nichts nachträglich ändern/überschreiben/löschen.

Du müsstest also die Datei kopieren, also lesend von einer ZIP, schreibend in eine Neue, und beim Kopieren deine Änderungen vornehmen.



Wenn die Dateigröße egal ist, dann einfach die Datei nochmal anhängen (mit dem gleichen Dateinamen) und beim entpacken überschreiben lassen, bzw. jeweils die letzte Version auslesen.

Ich hab es selber noch nicht ausprobiert, aber Delphi 11 soll nun auch Dateien aus dem Archiv entfernen können (delete):

https://docwiki.embarcadero.com/Libr...ZipFile.Delete

KodeZwerg 4. Dez 2021 23:09

AW: TZipFile
 
Hallo, ich habe es selbst noch nicht ausprobiert aber bin auf diesen code gestossen, vielleicht funktioniert es für nicht-Delphi-11?
stackoverflow.com
Delphi-Quellcode:
type
  TZipFileHelper = class helper for TZipFile
    procedure Delete(FileName: string);
  end;

{ TZipFileHelper }

procedure TZipFileHelper.Delete(FileName: string);
var
  i, j: Integer;
  StartOffset, EndOffset, Size: UInt32;
  Header: TZipHeader;
  Buf: TBytes;
begin
  i := IndexOf(FileName);
  if i <> -1 then begin
    // Find extents for existing file in the file stream
    StartOffset := Self.FFiles[i].LocalHeaderOffset;
    EndOffset := Self.FEndFileData;
    for j := 0 to Self.FFiles.Count - 1 do begin
      if (Self.FFiles[j].LocalHeaderOffset > StartOffset) and
         (Self.FFiles[j].LocalHeaderOffset <= EndOffset) then
        EndOffset := Self.FFiles[j].LocalHeaderOffset;
    end;
    Size := EndOffset - StartOffset;
    // Update central directory header data
    Self.FFiles.Delete(i);
    for j := 0 to Self.FFiles.Count - 1 do begin
      Header := Self.FFiles[j];
      if Header.LocalHeaderOffset > StartOffset then begin
        Header.LocalHeaderOffset := Header.LocalHeaderOffset - Size;
        Self.FFiles[j] := Header;
      end;
    end;
    // Remove existing file stream
    SetLength(Buf, Self.FEndFileData - EndOffset);
    Self.FStream.Position := EndOffset;
    if Length(Buf) > 0 then
      Self.FStream.Read(Buf[0], Length(Buf));
    Self.FStream.Size := StartOffset;
    if Length(Buf) > 0 then
      Self.FStream.Write(Buf[0], Length(Buf));
    Self.FEndFileData := Self.FStream.Position;
  end;
end;
Aufruf:
Delphi-Quellcode:
ZipFile.Delete('document.txt');
ZipFile.Add(SS, 'document.txt');
Viel Erfolg!

Willie1 5. Dez 2021 17:25

AW: TZipFile
 
Hallo KodeZwerg,
da hast du was Gutes bei Overflow gefunden. Ich werde es testen, bin aber sicher, dass es geht. Da habe ich schon oft Gutes gefunden.
Ich habe nur ein Problem: Bei dieser Methode wird wohl nur der Header gelöscht, die Datei bleibt. Mein von mir gegangener Weg wird bei Overflow genau so erwähnt. Bei 80 Dateien geht das sehr schnell und Speicherplatz auf der Festplatte ist kein Thema mehr.
Mein Ansatz ist richtig, könnt ihr erkennen, was an meinem Quelltext falsch ist. Sorry für meine Hartnäckigkeit.
Ich werde ein Archiv mit 80 Dateien mit dem Windows-Explorer packen und dann mit TZipFile und die Größe vergleichen.
Getan: Mit Windows: 87 KB mit TZipFile.Add: 90 KB. 75 Dateien mit jeweils 2777/2939 Bytes.

Willie.

Jumpy 7. Dez 2021 09:39

AW: TZipFile
 
Hat nichts mit deinem Problem zu tun, aber wenn du die Funktion für nur eine Datei so abänderst, musst du das Problem anschließend nur in einer Funtion beheben, hast also nicht so viel doppelten Code.

Delphi-Quellcode:
procedure TWZZipFile.AddandOverride(const aFilename: string; const ArchiveFileName: string);
var s:TStringlist;
begin
  s:=TStringlist.create;
  s.Add(aFilename);
  AddandOverride(s, ArchiveFileName);
  s.Free;
end;
Zum Problem: Ich hab noch nicht mit TZipFile gearbeitet, aber kann das hinzufügen zum Archiv und direkt danach das löschen in einem Zug vielleicht das Problem sein:
Delphi-Quellcode:
  for i := Low(List) to High(List) do begin
        Add(List[i]);
        TFile.Delete(List[i]);
      end;
Machen nich die Ganzen Zip-Dinger auch eine Validierung? Geht das wenn die Datei schon gelöscht ist?

Willie1 8. Dez 2021 18:43

AW: TZipFile
 
Zitat:

Zitat von Jumpy (Beitrag 1498732)
Hat nichts mit deinem Problem zu tun, aber wenn du die Funktion für nur eine Datei so abänderst, musst du das Problem anschließend nur in einer Funtion beheben, hast also nicht so viel doppelten Code.

Delphi-Quellcode:
procedure TWZZipFile.AddandOverride(const aFilename: string; const ArchiveFileName: string);
var s:TStringlist;
begin
  s:=TStringlist.create;
  s.Add(aFilename);
  AddandOverride(s, ArchiveFileName);
  s.Free;
end;

Du hast recht.
Zitat:

Zum Problem: Ich hab noch nicht mit TZipFile gearbeitet, aber kann das hinzufügen zum Archiv und direkt danach das löschen in einem Zug vielleicht das Problem sein:
Delphi-Quellcode:
  for i := Low(List) to High(List) do begin
        Add(List[i]);
        TFile.Delete(List[i]);
      end;
Machen nich die Ganzen Zip-Dinger auch eine Validierung? Geht das wenn die Datei schon gelöscht ist?
Die Zip-Datei wird neu geschrieben, sie wird nur immer größer. Wi.

Willie1 9. Dez 2021 17:03

AW: TZipFile
 
Hallo,
ich hab' den Fehler gefunden!
Delphi-Quellcode:
      Open(TempName, zmWrite); //hier liegt der Fehler
      for i := Low(List) to High(List) do begin
        Add(List[i]);//  <-----------------
        TFile.Delete(List[i]);
      end;
      Close;
ich benutze die Instanz TZipFile zweimal, einmal zum Auspacken des alten Zip und einmal zum Schreiben des neuen Zip. Ich war davon aus gegangen, dass mit Open Close ausgelöst wird (so steht es in der Hilfe) und das alte Archiv geschlossen wird. Das ist aber nicht so. Die alten Dateien werden nicht mehr "verlinkt", stehen aber noch im neuen Archiv. Deshalb wird es immer größer. So ist es mir zunächst nicht aufgefallen, weil es funktioniert.
Delphi-Quellcode:
  if Done then begin
      ZipFi := TZipFile.Create;//  <--- Neu
      List := TDirectory.GetFiles(TempPa);
      TempName := ExtractFilePath(ArchiveFilename) + ExtractFilename(TPath.GetTempFileName);
      ZipFi.Open(TempName, zmWrite);
      for i := Low(List) to High(List) do begin
        ZipFi.Add(List[i]);
        TFile.Delete(List[i]);
      end;
      ZipFi.Free;
    end;
So ist es richtig.
Es stellt sich mir die Frage: liegt das an meinen Programmierkünsten oder haben die "Delphi-Bauer" etwas übersehen?
Gruß Willie,

Hoffentlich seit ihr hier noch dabei.


Alle Zeitangaben in WEZ +1. Es ist jetzt 18:38 Uhr.
Seite 1 von 2  1 2      

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