ZIP file format
A ZIP archive — also the container format underlying docx/xlsx/pptx, jar, apk and epub.
- MIME type
- application/zip
- Extensions
- .zip
- Category
- Archives & compression
Magic-number signature
| 0x00000000 | 504B0304 | PK·· | 'PK' local-file header |
About the ZIP format
ZIP is the most widely used general archive format and, crucially, the container behind a whole family of formats (Office documents, Java JARs, Android APKs, EPUB books). A local file entry begins with 'PK' followed by 03 04.
Header layout, byte by byte
| Offset | Length | Field | Meaning |
|---|---|---|---|
| 0 | 4 | Local file header signature | 50 4B 03 04 — 'PK' after Phil Katz, then 3 and 4. Each stored file begins with one of these, so a multi-file archive contains many of them; only the one at offset 0 is at a fixed position. |
| 4 | 2 | Version needed to extract | Minimum reader version times ten: 10 means stored entries only, 20 means deflate and is the value you will see almost everywhere, 45 means ZIP64, 63 means AES or LZMA. Little-endian, like every number in a ZIP. |
| 6 | 2 | General purpose bit flag | Bit 0 marks the entry encrypted. Bit 3 says the CRC and both sizes are zero here and follow the data instead, which is why streamed ZIPs show zeroes in a hex dump. Bit 11 declares the file name UTF-8. |
| 8 | 2 | Compression method | 0 is stored, meaning the bytes that follow are the file itself; 8 is deflate. 12 bzip2, 14 LZMA, 93 Zstandard and 99 AES exist but far fewer readers accept them. |
| 10 | 2 | Last modified time | MS-DOS packed time: 5 bits of hours, 6 of minutes, 5 of seconds counted in twos. Two-second resolution and no time zone at all, which is why extracted files so often carry a timestamp an hour off. |
| 12 | 2 | Last modified date | MS-DOS packed date: 7 bits of year counted from 1980, 4 of month, 5 of day. Nothing before 1980 can be represented, so archived-from-tape files land on 1980-01-01. |
| 14 | 4 | CRC-32 | CRC-32 of the uncompressed data. This is the value an extractor compares against after inflating, and the one behind every 'CRC failed' message on a damaged entry. |
| 18 | 4 | Compressed size | How many bytes of compressed data follow the header and the variable-length fields. FF FF FF FF means the real value lives in a ZIP64 extra field instead. |
| 22 | 4 | Uncompressed size | The original size, with the same ZIP64 escape hatch. Both size fields read zero whenever general purpose bit 3 is set, because they have been moved after the data. |
| 26 | 2 | File name length | Byte length of the name that follows — call it n. Names are stored with forward slashes and never a leading slash, so an entry that begins with one is a path-traversal attempt. |
| 28 | 2 | Extra field length | Byte length of the extra-field block — call it m. It carries ZIP64 sizes, Unix permissions, high-precision timestamps and, on macOS-written archives, a great deal of alignment padding. |
| 30 | variable | File name | n bytes of path, and the single most useful thing in the whole header: it is what separates a docx from an apk from an epub, none of which differ by a single byte before this point. |
| -22 | 4 | End of central directory signature | 50 4B 05 06. The fixed part of the EOCD record is 22 bytes, so with an empty archive comment it starts exactly 22 bytes from the end. A comment pushes it further back and readers then have to scan backwards for it. |
| -6 | 4 | Offset of the central directory | Where the central directory begins, counted from the start of the file, under the same empty-comment caveat. Readers start here rather than at offset 0 — which is why an archive with a perfectly healthy first header can still refuse to open. |
Telling it apart from its neighbours
| Easily confused with | How to tell |
|---|---|
| EPUB | The strictest test in the family, because EPUB's OCF container spec pins the bytes down: the first entry must be named 'mimetype', stored uncompressed, with no extra field. So an EPUB reads 50 4B 03 04 at offset 0, method 0 at offset 8, name length 8 at 26, extra length 0 at 28, 'mimetype' at 30 and the literal string application/epub+zip at offset 38. A plain ZIP will not match all six. |
| Word document (docx) | Byte-identical through the local header; the difference is entirely in the names the central directory lists. An OOXML package must contain [Content_Types].xml at the archive root, and Word writes it as the first entry, so offset 30 usually reads that name. Then word/document.xml means docx, xl/workbook.xml means xlsx and ppt/presentation.xml means pptx. |
| Android APK | Also a ZIP with no distinguishing header bytes. An APK holds AndroidManifest.xml and at least one classes.dex at the archive root, and that manifest is Android binary XML rather than text, so its data begins 03 00 08 00. APKs signed with scheme v2 or later also carry the 16-byte marker 'APK Sig Block 42' between the last entry and the central directory. |
| Java JAR | A JAR is a ZIP whose central directory lists META-INF/MANIFEST.MF. Java's own JarInputStream only finds the manifest when it is the first or second entry, so every build tool writes it up front; a .jar with the manifest buried late still opens as a ZIP but loads as though it had none. |
| GZIP | Constantly confused because both are 'compressed', yet there is nothing to confuse at byte level: gzip is 1F 8B and holds one stream with no directory whatsoever. A .tar.gz cannot be listed without decompressing the whole thing, while a ZIP can be listed from its last few hundred bytes. |
How these files break
- Truncated at the tail. Every local header survives, so a hex dump looks perfectly healthy from offset 0, and yet nothing will open the file — readers start from the EOCD at the end and it is gone. Recovery means scanning forward for 50 4B 03 04 and rebuilding the directory from the local headers.
- Prepended bytes. Self-extracting stubs are legal and common, but an HTML error page saved under a .zip name does the same thing: the central directory's offsets are now measured from the wrong base. Some readers auto-correct by computing the shift, others report every entry as corrupt.
- Text-mode transfer. The same line-ending translation that ruins PNGs turns 0D 0A into 0A inside compressed data. The header still parses and the entry names still list correctly, so the failure surfaces only as a CRC mismatch at extraction time.
- The 4 GiB and 65535-entry walls. A writer that never emits ZIP64 wraps the 32-bit size fields and the 16-bit entry count modulo their range. The archive stays well-formed and the numbers are simply wrong: an entry claiming 300 MB that extracts to 4.3 GB is this bug.
- Mojibake in file names. Before bit 11 of the general purpose flag existed, names were written in the creator's local code page. A Windows-made archive full of Japanese file names lists as garbage on Linux even though not one byte of the file is damaged.
Where the format stands today
ZIP stopped being merely an archive format a long time ago and became a container format, which is why it is not going anywhere. Every OOXML document, every EPUB, every JAR, APK, XPI and ODF file is a ZIP with a required inner layout. As a plain archiver it has been beaten on compression ratio by 7z, xz and Zstandard for two decades, and tar.gz won on Unix because it preserves permissions and symlinks that ZIP represents only awkwardly through extra fields. What keeps ZIP first choice is random access: because the directory sits at the end rather than being interleaved, a reader can list an archive and pull one file out of it without touching the rest. That is exactly what an Android runtime or a word processor needs, and exactly what a compressed tarball cannot do.
Open ZIP files on this site
Every one of these runs in your browser — the file never leaves your machine.
Related formats
Formats that are easy to confuse with ZIP — compare their leading bytes.
| Format | First bytes | Extension |
|---|---|---|
| GZIP | 1F 8B | .gz |
| Word document (docx) | 50 4B 03 04 | .docx |
| Android APK | 50 4B 03 04 | .apk |
| Java JAR | 50 4B 03 04 | .jar |
| EPUB | 50 4B 03 04 | .epub |
| 7-Zip | 37 7A BC AF 27 1C | .7z |