![]() |
ZIP-Forge Datei zippen im MemoryStream (geöffnete Dateien)
Ich benutze seit Neuestem privat ZIP-Forge zum Zippen von Dateien in meinem Projekt.
Da das normale Zippen zulange dauerte habe ich auf das Zippen direkt im Speicher über einen TMemoryStream umgestellt. Jetzt ist mir aufgefallen, dass normal geöffnete Dateien ohne besondere Schutz-Rechte nicht in den Speicher geschrieben werden können. Genauer gesagt ist Datei Projekt.exe in Verzeichnis ABC offen und ich zippe mit Projekt.exe das Verzeichnis ABC. Projekt.exe kann jetzt nicht gezippt werden. Gibt es hier einen Schalter den ich einstellen kann, dass die Datei nur im Lese-Modus geöffnet wird und nicht auch im Schreibmodus? So sieht das Originalbeispiel aus und so verwende ich es auch
Delphi-Quellcode:
Ohne Memorystream ist alles OK und auch normal geöffnete Dateien können gezippt werden.
var
Archiver: TZipForge; ms: TMemoryStream; begin // create ZipForge object Archiver := TZipForge.Create(nil); // create memory stream ms := TMemoryStream.Create; try // create a new archive in the memory stream (specify False to open an existing archive) Archiver.OpenArchive(ms, True); // save a file into the archive Archiver.AddFiles('c:\file.txt'); // close archive Archiver.CloseArchive(); except on E: Exception do begin Writeln('Error: ' + E.Message); end; end; ms.Free; Archiver.Free; end. |
AW: ZIP-Forge Datei zippen im MemoryStream (geöffnete Dateien)
Hallo,
hast die Version nicht mit den Quellen? |
AW: ZIP-Forge Datei zippen im MemoryStream (geöffnete Dateien)
Kann das Teil nicht zufällig auch ein AddStream? Dann könntest Du das ja über den Weg selbst erledigen... auch ohne Sourcen...
|
AW: ZIP-Forge Datei zippen im MemoryStream (geöffnete Dateien)
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:
Zitat:
|
AW: ZIP-Forge Datei zippen im MemoryStream (geöffnete Dateien)
Ich habe die Sourcen leider auch nicht.
Aber wenn man das Archiv mit einem Stream "öffnet"
Delphi-Quellcode:
... und dann Dateien "hinzufügt"
ZipForge1.OpenArchive(aMemoryStream, True);
Delphi-Quellcode:
... ackert der intern dann nicht auch AddToStream ab?
ZipForge1.AddFiles();
|
AW: ZIP-Forge Datei zippen im MemoryStream (geöffnete Dateien)
Zitat:
|
AW: ZIP-Forge Datei zippen im MemoryStream (geöffnete Dateien)
Ich habe das gerade mal so versucht
Delphi-Quellcode:
Leider ist das Archiv dann leer. Ich habe bestimmt einen sau-blöden Fehler gemacht und sehe ihn nicht.
ZipForge1.OpenArchive(fmCreate);
// Statt ZipForge1.AddFiles(aFileName); nun ... // for ... alle meine Daten aFileStream := TFileStream.Create(aFileName, fmOpenRead); // fmOpenRead statt fmOpenWrite ZipForge1.AddFromStream(aFileName, aFileStream); aFileStream.Free; // ende for ZipForge1.CloseArchive; Das Archiv war nur leer, weil ich am Ende der For-Schleife noch ein aMemoryStream.SaveToFile() vom alten MemoryStream stehen hatte. Edit: ich sehe gerade ZipForge1.AddFromStream() hat leider einen Bug und ist unbrauchbar. Die Option
Delphi-Quellcode:
wird bei AddFromStream komplett ignoriert.
ZipForge1.Options.StorePath := spRelativePath;
Außer aber man entfernt durch String-Replace das BaseDir aus aFileName, dann ist es OK. |
AW: ZIP-Forge Datei zippen im MemoryStream (geöffnete Dateien)
Das funktioniert jetzt soweit sehr gut.
Auch wenn es umständlich ist.
Delphi-Quellcode:
Einzige unschöne Nebenwirkung ist, dass wenn man große Dateien zippen möchte man die Meldung bekommt "Zu wenig Arbeitsspeicher".
aMemoryStream := TMemoryStream.Create;
ZipForge1.OpenArchive(aMemoryStream, True); aFileStream := TFileStream.Create(aCurrItem.sSourceDirItem, fmOpenRead); try ZipForge1.AddFromStream(StringReplace(aFileName, ZipForge1.BaseDir, ''), aFileStream); finally aFileStream.Free; end; ZipForge1.CloseArchive; aMemoryStream.SaveToFile(ZipForge1.FileName); Aber das ist wohl der bittere Nebengeschmack denke ich. Ab circa 500MB im Taskmanager bekomme zumindest ich die Meldung. Dann werde ich wohl jetzt eine Art Kreuzung einbauen die bei Verzeichnissen, sagen wir mal, bis zu Größe-X mit dem FileStream zippt und sonst normal. |
AW: ZIP-Forge Datei zippen im MemoryStream (geöffnete Dateien)
Zitat:
|
AW: ZIP-Forge Datei zippen im MemoryStream (geöffnete Dateien)
Daran habe ich noch nicht gedacht. Aber nein, da passiert es nicht.
Ich habe eben den Compiler-Schalter {$SETPEFLAGS IMAGE_FILE_LARGE_ADDRESS_AWARE} gefunden. Mit dem klappt auch das Komprimieren von 500MB+ großen Dateien. Ohne ihn nicht. Kann dieser Schalter irgendwelche Nebenwirkungen hervorufen? |
AW: ZIP-Forge Datei zippen im MemoryStream (geöffnete Dateien)
Ich habe eben zufälligerweise auch mitbekommen, dass das Programm die eigene Programmdatei trotzdem nicht zippen kann, obwohl ich die Datei mit fmOpenRead in den Stream lade.
Die Fehlermeldung lautet, dass das Handle ungültig sei. |
AW: ZIP-Forge Datei zippen im MemoryStream (geöffnete Dateien)
Wäre mal zu probieren, die eigene Programmdatei vor dem Zippen per ScriptingHost (ShFileOperation) zu kopieren und die kopierte Datei zu zippen. Solange eine Exe läuft, hat das System einen exklusiven Zugriff auf die Datei. Da kommst du nicht ran mit einem Programm das im Benutzerkontext läuft. Der ScriptingHost läuft im System und sollte es können.
Delphi-Quellcode:
Bzgl. des Speicherproblems dürfte es eigentlich selbsterklärend sein: Je nach dem wie die ZIP-Routinen implementiert sind alloziieren sie evtl. so viel Speicher wie die unkomprimierten Daten groß sind. Die 500 MB sind ja nur das Endresultat des Komprimierens. Bei einem 32-Bit-System wäre da spätestens bei 3 GB RAM Schluss, wahrscheinlich aber eher bei 2 GB. Es gibt richtige Streamzipper die können das besser, aber auch da ist irgendwann Sense bei 32 Bit. Auch ein Grund warum wir bei uns nur noch 64 Bit ausliefern.
uses Winapi.Shellapi;
function dwCopyDirFile(const Src, Dst: String; const GUI, SimpleGUI, CopyConfirmation, MkDirConfirmation, ErrorGUI: Boolean; var UserHasCancelled: Boolean): Boolean; var FOS : TSHFileOpStruct; Flags: Word; begin Flags:= 0; if GUI then if SimpleGUI then Flags:= Flags or FOF_SIMPLEPROGRESS else Flags:= Flags or FOF_SILENT; if not CopyConfirmation then Flags:= Flags or FOF_NOCONFIRMATION; if not MkDirConfirmation then Flags:= Flags or FOF_NOCONFIRMMKDIR; if not ErrorGUI then Flags:= Flags or FOF_NOERRORUI; ZeroMemory(@FOS,SizeOf(FOS)); with FOS do begin wFunc := FO_COPY; fFlags := Flags; pFrom := PChar(ExcludeTrailingBackslash(Src) + #0); pTo := PChar(ExcludeTrailingBackslash(Dst)); end; RESULT := (0 = ShFileOperation(FOS)); UserHasCancelled:= FOS.fAnyOperationsAborted; end; |
AW: ZIP-Forge Datei zippen im MemoryStream (geöffnete Dateien)
Danke das werde ich mal ausprobieren.
Das Speicherproblem habe ich vorerst mit dem Setzen von {$SETPEFLAGS IMAGE_FILE_LARGE_ADDRESS_AWARE} behoben. Der Speicherverbrauch geht jetzt schon einmal bis 1GB und mehr. Vorher konnte eine 500MB Datei nicht komprimiert werden, jetzt schon. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:05 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