ZIP

ZIP-Archiv

Container-Format mit DEFLATE β€” von hinten gelesen

ZIP ist ein Archiv- und Container-Format, das 1989 von Phil Katz (PKWARE) entworfen wurde. Eine ZIP-Datei bΓΌndelt mehrere Dateien und Ordner und komprimiert sie β€” ΓΌblicherweise mit DEFLATE, demselben Verfahren, das auch in PNG steckt.

Das Besondere am Aufbau: ZIP wird β€žvon hintenβ€œ gelesen. Am Dateiende steht das End of Central Directory (EOCD). Es verweist auf das Central Directory β€” ein Inhaltsverzeichnis aller enthaltenen EintrΓ€ge. So lΓ€sst sich ein Archiv schnell durchsuchen, ohne alle Daten zu lesen.

Jeder Eintrag besteht aus einem Local File Header direkt vor den komprimierten Daten und einem zugehΓΆrigen Eintrag im zentralen Verzeichnis. Alle Mehrbyte-Zahlen sind Little-Endian.

Magic Number: 50 4B 03 04 Β β†’Β  P K \x03 \x04

🧩 Aufbau des Archivs

Header + Daten je Datei, danach das zentrale Inhaltsverzeichnis und der Abschluss.

SignaturBilddatenMetadatenEnde
Local File Header #1
30 Byte + Name
50 4B 03 04 …
Signatur 'PK\x03\x04', Methode, CRC-32, Grâßen, Dateiname. Steht direkt vor den Daten.
Komprimierte Daten #1
variabel
…DEFLATE…
Der eigentliche Dateiinhalt, meist DEFLATE-komprimiert (Methode 8).
… weitere EintrΓ€ge …
variabel
PK 03 04 …
Pro enthaltener Datei wiederholt sich Header + Daten.
Central Directory
variabel
50 4B 01 02 …
Inhaltsverzeichnis: ein Eintrag ('PK\x01\x02') je Datei mit Offset zum Local Header.
End of Central Directory
22 Byte + Kommentar
50 4B 05 06 …
Abschluss ('PK\x05\x06'): Anzahl EintrÀge, Grâße & Offset des Central Directory.

πŸ“ Ablaufdiagramm (ASCII)

Wichtig: Ein Reader beginnt am Ende der Datei beim EOCD.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ PK 03 04   Local File Header  (Datei A)                      β”‚
β”‚            β”œβ”€ Methode, CRC-32, comp/uncomp Grâße, Name       β”‚
β”‚ <DEFLATE>  komprimierte Daten von Datei A                    β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ PK 03 04   Local File Header  (Datei B)                      β”‚
β”‚ <DEFLATE>  komprimierte Daten von Datei B                    β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ PK 01 02   Central Directory Entry (Datei A) ─┐ Offset ──┐   β”‚
β”‚ PK 01 02   Central Directory Entry (Datei B)  β”‚          β”‚   β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜          β”‚   β”‚
β”‚ PK 05 06   End Of Central Directory  β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚            (#EintrΓ€ge, Grâße & Offset des Central Directory)  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        β–² Leser startet HIER (am Dateiende) und springt rΓΌckwΓ€rts

πŸ“Š Tabellen & Referenz

Die drei Kernsignaturen (Little-Endian)

HexASCIIRecord
50 4B 03 04PKβ™₯♦Local File Header
50 4B 01 02PK☺☻Central Directory Header
50 4B 05 06PK♣♠End of Central Directory
50 4B 07 08PKβ€’β€’Data Descriptor (optional)

Wichtige Kompressionsmethoden

CodeMethodeBemerkung
0Storedunkomprimiert (nur gespeichert)
8DeflateStandard β€” LZ77 + Huffman (wie PNG)
9Deflate64erweiterte Variante
12BZIP2selten
14LZMAhohe Kompression, optional

⌨️ C-Strukturen & Auslese-Code

Die struct-Definitionen entsprechen exakt dem Byte-Layout der Records.

Local File Header (Little-Endian!) Β· c
#include <stdint.h>

#pragma pack(push, 1)          /* exakt am Byte-Layout ausrichten */
typedef struct {
    uint32_t signature;        /* 0x04034B50  ("PK\3\4")          */
    uint16_t version_needed;
    uint16_t flags;
    uint16_t compression;      /* 0 = Stored, 8 = Deflate          */
    uint16_t mod_time;
    uint16_t mod_date;
    uint32_t crc32;            /* PrΓΌfsumme der unkompr. Daten     */
    uint32_t comp_size;        /* komprimierte Grâße               */
    uint32_t uncomp_size;      /* Originalgrâße                    */
    uint16_t name_len;         /* LΓ€nge des Dateinamens            */
    uint16_t extra_len;        /* LΓ€nge des Extra-Feldes           */
    /* char filename[name_len]; */
    /* char extra[extra_len];   */
} zip_local_header_t;
#pragma pack(pop)

ℹ️ Achtung: ZIP speichert alle Zahlen Little-Endian. signature == 0x04034B50, wenn als uint32 gelesen.

Central Directory & End of Central Directory Β· c
#pragma pack(push, 1)
typedef struct {
    uint32_t signature;        /* 0x02014B50  ("PK\1\2")          */
    uint16_t version_made_by;
    uint16_t version_needed;
    uint16_t flags;
    uint16_t compression;
    uint16_t mod_time, mod_date;
    uint32_t crc32;
    uint32_t comp_size, uncomp_size;
    uint16_t name_len, extra_len, comment_len;
    uint16_t disk_start;
    uint16_t internal_attr;
    uint32_t external_attr;
    uint32_t local_header_offset; /* Position des Local Headers   */
} zip_central_header_t;

typedef struct {
    uint32_t signature;        /* 0x06054B50  ("PK\5\6")          */
    uint16_t disk_number;
    uint16_t cd_start_disk;
    uint16_t cd_entries_disk;
    uint16_t cd_entries_total; /* Anzahl EintrΓ€ge im Archiv        */
    uint32_t cd_size;          /* Grâße des Central Directory      */
    uint32_t cd_offset;        /* Offset zum Central Directory     */
    uint16_t comment_len;
} zip_eocd_t;
#pragma pack(pop)
EOCD am Dateiende finden Β· c
#include <stdio.h>

/* Sucht 0x06054B50 ("PK\5\6") rΓΌckwΓ€rts und liefert dessen Offset. */
long zip_find_eocd(FILE *f) {
    fseek(f, 0, SEEK_END);
    long size = ftell(f);
    long max_back = size < 65557 ? size : 65557;  /* 22 + max. Kommentar */

    for (long off = size - 22; off >= size - max_back; off--) {
        fseek(f, off, SEEK_SET);
        uint32_t sig;
        fread(&sig, 4, 1, f);
        if (sig == 0x06054B50) return off;  /* gefunden */
    }
    return -1;  /* keine gΓΌltige ZIP-Struktur */
}

ℹ️ Da ein Kommentar folgen kann, sucht man die EOCD-Signatur rΓΌckwΓ€rts vom Dateiende.

πŸ—œοΈ Kompression

ZIP nutzt standardmÀßig DEFLATE (LZ77 + Huffman) β€” dasselbe Verfahren wie die IDAT-Chunks in PNG. Jeder Eintrag kann eine eigene Methode haben (z. B. β€žStoredβ€œ ohne Kompression). Verwandt ist auch LZW, das in GIF zum Einsatz kommt.

πŸ’‘ Wissenswert

✨ZIP wird von hinten gelesen: Erst das End of Central Directory, dann das Inhaltsverzeichnis, dann gezielt die Dateien.
✨Office-Formate (.docx, .xlsx, .pptx), .jar, .apk und .epub sind in Wahrheit ZIP-Archive mit fester Ordnerstruktur.
✨Die Signatur 'PK' sind die Initialen des Erfinders Phil Katz.
✨DEFLATE in ZIP ist exakt dasselbe Verfahren wie in PNG-IDAT-Chunks β€” nur der Container drumherum unterscheidet sich.
← ZurΓΌck zur Übersicht