Diskussion zum Artikel "Die Arbeit mit ZIP-Archiven in MQL5 ohne Bibliotheken von Drittanbietern" - Seite 8

 
Ist geplant, eine Funktion zum Dekomprimieren einer mit dem GZIP-Algorithmus komprimierten Zeichenkette hinzuzufügen?
 
Ivan Titov CryptEncode(CRYPT_ARCH_ZIP) dekomprimieren. Es ist nicht schwer, dies selbst zu tun, ohne Bibliotheken von Drittanbietern zu verwenden, denn der Kompressionsalgorithmus ist derselbe, nämlich Deflate (in MQL hat er einen nicht sehr guten Bezeichner CRYPT_ARCH_ZIP). Es ist schade, dass es keinen speziellen Artikel "Arbeiten mit GZip-Archiv mit MQL5-Tools" gibt. Im Allgemeinen ist dies nicht die Aufgabe einer Systemfunktion, sondern die Aufgabe einer speziellen MQL-Bibiloteka, die Deflate um das Gzip-Format wickelt.
 
Jacobie Nycambren Barksdale #:
Gibt es dazu Neuigkeiten? Ich stoße auf Fehler

ZipLocalHeaderOpen' hat einen Konstruktor und kann nicht als Union-Mitglied verwendet werden ZipHeader.mqh 52 23

Jacobie, Stanislav Korotky hat hier ein Paket veröffentlicht, das diese Zip-Bibliothek enthält, mit einigen Korrekturen.

Ich habe es getestet, und so weit ist ziemlich gut funktioniert.

MQL5 Program Packer
MQL5 Program Packer
  • www.mql5.com
This is MQL5 project packer: assemble all source and resource files from dependencies into a single ZIP.
 

Ich bin auf ein Archiv gestoßen, das CZip nicht dekomprimieren konnte. Gleichzeitig dekomprimieren 7ZIP und Windows archiver ohne Probleme.
Druckte die Größe der komprimierten Daten aus - es stellte sich heraus, dass sie einige zehn Megabyte kleiner war als das Archiv (und es gibt nur eine Datei darin).

CompressedSize:76964920 
Ich begann zu suchen, wo die Größe berechnet wird, und fand sie in der Funktion FindZipFileSize().

Experimentiert...
Es stellte sich heraus, dass das Archiv korrekt entpackt wird, wenn man alle end_size-Daten als Datengröße zurückgibt. Offenbar bestimmt der Code beim Entpacken selbst das Ende der Daten, anstatt sich auf die Antwort dieser Funktion zu verlassen. Die Hauptsache ist, dass sie nicht kleiner sein sollte. Man könnte es so lassen, aber es stellt sich heraus, dass die Funktion nutzlos ist, was unwahrscheinlich ist. Und vielleicht scheitern auch andere Archive...
Ein weiteres Experiment hat gezeigt, dass, wenn man die Zeilen auskommentiert

    // if(muster == cdheader) 
    // Pause;

Das Archiv beginnt auch zu entpacken. Die Datenmenge liegt nahe bei 100%.

CompressedSize:106638447 
Es stellt sich heraus, dass das Archiv uint cdheader = 0x504b0102; hat, und dies ist ein Teil der komprimierten Daten, nicht ein Label des Endes.

Haben Sie einen Fehler bei der Kennzeichnung gemacht? Ich habe ein solches Label bei der Internetsuche gefunden. Vielleicht sollte es auf eine andere Weise verarbeitet werden, anstatt die Daten damit zu kürzen, ich habe 30MB gekürzt.

Funktion arbeitet mit dieser Datei: (Datei \Include\Zip\Zip\Zip.mqh)

int CZip::FindZipFileSize(uchar &zip_array[],int offset)
{
   uint pattern =    0;
   int size =        0;
   uint header =     0x504b0304;
   uint cdheader =   0x504b0102;
   uint mask =       0xffff0000;
   int end_size = ArraySize(zip_array)-offset;
   //Dieser Ringpuffer basiert auf einer Byte-Linksverschiebung: x = x << 8
   for(; size < end_size; size++)
   {
      pattern = pattern << 8;
      uint nbyte = zip_array[offset+size];
      pattern = pattern | nbyte;
      //Überprüfung der oberen 2 Bytes
      if((pattern & mask)!=(0x504b << 16))
         continue;
      //wenn zwei obere Bytes gleich 0x504b sind, alle Signaturen prüfen
      if(pattern == header)
         break;
    // if(muster == cdheader)
    // Pause;
   }
   //Keine Signaturen gefunden. Schlechtes Format.
   if(size == end_size-1)
      return 0;
   //Rückgabegröße - Größe der Unterschrift.
   return size-sizeof(ZIP_LOCAL_HEADER)+1;
}
Ich kann Ihnen die Archivdatei in einer privaten Nachricht zusenden, wenn Sie daran interessiert sind, es herauszufinden.
 

Ein weiterer Fehler bei einer anderen Datei. Diesmal half das Auskommentieren der Zeilen

// if(Muster == Kopfzeile)
// Pause;

D.h. der Code uint header = 0x504b0304; kommt auch im Archivinhalt vor und wird von 7Zip, Windows und dieser korrigierten Version von CZip erfolgreich entpackt.

Da beide Schleifenexits deaktiviert sind, ist die Schleife überflüssig geworden, sie kann gelöscht und zurückgegeben werden:

return ArraySize(zip_array)-offset-sizeof(ZIP_LOCAL_HEADER)+1;

Offensichtlich liegt ein Fehler in dieser Funktion vor. Immerhin wird die Bedingung

   //Keine Signaturen gefunden. Schlechtes Format.
   if(size == end_size-1)
      return 0;

nie erfüllt werden, denn beim Verlassen der Schleife, wenn das Ende der Daten erreicht ist, wird size == end_size sein, nicht 1 weniger.

Daraufhin habe ich die Funktion auf eine Zeile gekürzt:

int CZip::FindZipFileSize(const uchar &zip_array[],int offset)
{
   /*uint pattern = 0;
 int size =0;
 uint header = 0x504b0304;
 uint cdheader =0x504b0102;
 uint mask = 0xffffff0000;
 int end_size = ArraySize(zip_array)-offset;
 //das ist ein Ringpuffer basierend auf Byte Linksverschiebung: x = x << 8
 for(; size < end_size; size++)
 {
 pattern = pattern << 8;
 uint nbyte = zip_array[offset+size];
 pattern = pattern | nbyte;
 //Überprüfung der oberen 2 Bytes
 if((pattern & mask)!=(0x504b << 16))
 continue;
 //wenn zwei obere Bytes gleich 0x504b sind, alle Signaturen prüfen
// if(pattern == header)
//break;
// if(muster == cdheader)
//break;
 }
 //Keine Signaturen gefunden. Schlechtes Format.
 if(size == end_size-1)
 return 0;
 //Return size - Signaturgröße.
 return size-size-sizeof(ZIP_LOCAL_HEADER)+1;
 */
   return ArraySize(zip_array)-offset-sizeof(ZIP_LOCAL_HEADER)+1;
}

Das Programm mit dieser Version der Funktion hat bereits 110 Archive für insgesamt 12 Gg heruntergeladen und alles erfolgreich entpackt.

Falls jemand Probleme mit dem Entpacken hat, kann er diese Version der Funktion ausprobieren.

 
Ich habe fast 300 Dateien heruntergeladen und entpackt. Und die Daten darin werden immer größer und haben die Größengrenze erreicht.
Die Datei sollte 1,8 Milliarden Elemente haben, aber sie ist auf 1,5 Milliarden gekürzt. Einige Daten sind verloren gegangen. Es ist seltsam, dass die Datei so kurz ist, denn Arrays können bis zu 2147483647 Elemente haben.
Die Terminalfunktion
erzeugt geschnittene Daten.
CryptDecode(CRYPT_ARCH_ZIP, m_file_puck, key, file_array);

Es gibt nichts, was man dagegen tun könnte...

Ich dachte, es sei möglich, in geraden kb/mb-Blöcken zu dekodieren - ich habe 1024, 1024*1024 und 1024*1024*10 eingegeben - es hat nicht funktioniert.

Ich werde Archive speichern müssen, sie dann manuell dekomprimieren und dann verarbeiten. Das ist lästig - ohne Automatisierung ((

Gibt es eine Möglichkeit, das Windows-Archivierungsprogramm zu verwenden? Mit WinExec in eine Datei entpacken und diese dann Zeile für Zeile einlesen. Auf diese Weise wird die Automatisierung erhalten bleiben. Aber nicht für den Markt.
 
Forester #:
Gibt es eine Möglichkeit, das Windows-Archivierungsprogramm zu verwenden? Verwenden Sie WinExec, um eine Datei zu entpacken, und lesen Sie sie dann Zeile für Zeile.

Das können Sie natürlich. Wo liegt das Problem? Vielleicht habe ich das falsch verstanden? Es gibt schon seit langem Konsolenarchivierungsprogramme wie UnRAR.exe, UnZip.exe usw.

 
Forester #:

Ein weiterer Fehler bei einer anderen Datei. Diesmal half das Auskommentieren der Zeilen

D.h. der Code uint header = 0x504b0304; kommt auch im Archivinhalt vor und wird von 7Zip, Windows und dieser korrigierten Version von CZip erfolgreich entpackt.

Da beide Schleifenexits deaktiviert sind, ist die Schleife überflüssig geworden, sie kann gelöscht und zurückgegeben werden:

Offensichtlich liegt ein Fehler in dieser Funktion vor. Immerhin ist die Bedingung

niemals erfüllt werden, denn beim Verlassen der Schleife, wenn das Ende der Daten erreicht ist, wird size == end_size sein, nicht 1 weniger.

Deshalb habe ich die Funktion auf eine Zeile gekürzt:

Das Programm mit dieser Version der Funktion hat bereits 110 Archive für insgesamt 12 Gg heruntergeladen und alles erfolgreich entpackt.

Falls jemand Probleme mit dem Entpacken hat, kann er diese Version der Funktion ausprobieren.

Ich kann davon ausgehen, dass man immer noch nach Labels suchen muss, aber nicht im Archivkörper, sondern zwischen den Dateien, wenn es mehrere davon gibt. Wahrscheinlich sollten die Archivlängen irgendwo aufgezeichnet werden....
Im Allgemeinen ist meine Lösung für meine Aufgabe mit 1 Datei im Archiv privat, wenn es mehrere davon gibt - vielleicht müssen Sie etwas anderes tun.

 
Forester #:

Ich kann davon ausgehen, dass die Bezeichnungen immer noch gesucht werden müssen, aber nicht im Archivkörper, sondern zwischen den Dateien, wenn es mehrere davon gibt. Wahrscheinlich sollten die Längen des Archivs irgendwo aufgezeichnet werden....
Im Allgemeinen ist meine Lösung für meine Aufgabe mit 1 Datei im Archiv privat, wenn es mehrere davon gibt - vielleicht ist es notwendig, etwas anderes zu tun.

Ich habe einen Ausdruck der komprimierten und unkomprimierten Größen gemacht, die in den Headern stehen sollten.
Die Dateien, die ich heruntergeladen habe - haben 0 0. Wenn size=0, dann wird FindZipFileSize(), wie oben beschrieben, aufgerufen.

Ich habe ein Archiv mit der 1. Datei mit einem normalen Archivierungsprogramm erstellt. Größen im Header:
46389587 376516461

Und ein weiteres Archiv mit 2 Dateien, einschließlich der zum ersten Archiv hinzugefügten Datei:
46981880 314725045
46389587 376516461

Bei beiden sind die Größen in den Headern angegeben und FindZipFileSize() wurde nicht aufgerufen.

Und die Dateien, die ich heruntergeladen habe (mit 0 0 in den Größen), wurden offenbar von einer Software erstellt, die die Größen nicht in die Header geschrieben hat.

Vielleicht ist meine Lösung, FindZipFileSize() zu verkürzen, universell.

 
Edgar Akhmadeev #:

Natürlich können wir das. Wo liegt das Problem? Vielleicht habe ich das falsch verstanden? Es gibt seit langem die Konsolenarchivierungsprogramme UnRAR.exe, UnZip.exe usw.

Ich habe das Entpacken über 7-zip gemacht (UnZip.exe wurde seit 2009 nicht mehr aktualisiert, über die Unterstützung auch von Win 7 wird nicht geschrieben).
Ich habe die Geschwindigkeit verglichen:
Diese CZIP-Bibliothek:

2025.06.14 20:59:06.758 Archiv erfolgreich geöffnet. Dateien insgesamt: 1.
2025.06.14 20:59:07.345 Ungezippt
587ms

7-zip:
2025.06.14 21:00:07.312 Start unzip durch 7-Zip.
2025.06.14 21:00:09.274 Entpackt mit 7-Zip. Dateigröße: 428.22 MB
1962 ms

Dies ist nur für das Entpacken der Datei mit Zurücksetzen auf die SSD-Disk. Sie müssen die Datei auch Zeile für Zeile vom Datenträger lesen.

Gesamtzeit vom Beginn bis zum Ende des Parsings:
Gesamtzeit: 10s 709ms
und
Gesamtzeit: 12s 892ms
Die Differenz beträgt 2s 183 ms.

Im Allgemeinen ist es vorzuziehen, diese CZIP-Bibliothek wegen der Geschwindigkeit zu verwenden, und wenn die Datei zu groß ist, andere Archivierungsprogramme zu benutzen.

Für mich bedeutet das bei ~1000 Dateien zu je 2s eine Ersparnis von 33 Minuten. Eigentlich mehr, da dies ein Beispiel mit der kleinsten Datei von 428 MB ist, CZIP entpackt Dateien bis zu ~1,7 GB.
Alles, was größer ist (bis zu 4 GB), wird von 7-zip verarbeitet. Die Ersparnis liegt also bei 1-1,5 Stunden.

Ich habe CZIP mit meinen Bearbeitungen getestet - 600+ Dateien auf 100 GB wurden ohne Fehler entpackt.