A ZIP archive is a run of records, each starting with a four-byte signature. Member data comes first and the index comes last, so a reader starts at the end of the file. This page gives the order of the records, their signatures, how a reader finds them and what can come before them. Later pages describe each record field by field.
Order of the records
APPNOTE sets this order. Parts marked “if used” may be absent.
0Local file headerPK 03 04, then the name and extra field30 bytes and more…Encryption header if the member is encryptedvaries…File data stored or compressedvaries…Data descriptor if flag bit 3 is set12 to 24 bytes…More members the same four parts for each filerepeated…Archive decryption header if the directory is encryptedvaries…Archive extra data recordPK 06 08, with certificates8 bytes and more…Central directory onePK 01 02header per member46 bytes and more each…Digital signaturePK 05 05, if used6 bytes and more…ZIP64 end of central directoryPK 06 06, if used56 bytes and more…ZIP64 locatorPK 06 07, with that record20 bytes…End of central directoryPK 05 0622 bytes and comment
Every archive has exactly one end of central directory record. A file holding only that record is a valid empty archive of 22 bytes. Every member has one local header and one central directory header. The central directory need not list members in the order their data appears, and a local header that no central header points to is not part of the archive.
Signatures
The first two bytes are always 50 4B, ASCII PK, for Phil
Katz. The table shows the bytes in file order, then the same value as APPNOTE writes
it, as a little-endian number.
| Bytes | Value | Record |
|---|---|---|
50 4B 03 04 | 0x04034B50 | Local file header |
50 4B 07 08 | 0x08074B50 | Data descriptor (optional signature); also the marker at the start of a split archive |
50 4B 30 30 | 0x30304B50 | Temporary marker of a split archive that needed only one segment |
50 4B 06 08 | 0x08064B50 | Archive extra data record |
50 4B 01 02 | 0x02014B50 | Central directory header |
50 4B 05 05 | 0x05054B50 | Digital signature |
50 4B 06 06 | 0x06064B50 | ZIP64 end of central directory record |
50 4B 06 07 | 0x07064B50 | ZIP64 end of central directory locator |
50 4B 05 06 | 0x06054B50 | End of central directory record |
An archive cannot be identified just by its first four bytes. A self-extracting archive starts with a program, and a file of any size can have an end record at the end. The reliable test is the one a reader performs anyway: find the end record, then check that the central directory is where it says.
How a reader finds things
- Search backwards from the end of the file for the end of central directory record.
- Look 20 bytes before it for a ZIP64 locator. If one is there, read the ZIP64 record it points to.
- From these records take the number of members and the size and offset of the central directory.
- Walk the central directory. Each header gives a member’s name, method, CRC-32, sizes and the offset of its local header.
- To read a member, go to its local header, read that header’s own name and extra lengths, and skip them to reach the data. The local header’s extra field can be a different length from the central header’s, so the central lengths are no guide.
A reader can also start at the beginning and walk the local headers one after the other. The two methods can give different answers, and only the central directory says what is in the archive.
Byte order and types
Every multi-byte number in a ZIP file is unsigned and little-endian, unless a field’s description says otherwise. A few mainframe and Macintosh extra fields have their own big-endian values, described with them. Strings are not terminated by a NUL; their length is stored separately.
Fixed fields are 2 or 4 bytes wide, so the largest values are 65,535 and 4,294,967,295. A field that overflows holds all ones and the real value moves to a ZIP64 field.
Data in front of an archive
Any bytes may come before the first local header. The usual case is a self-extracting archive: an executable stub followed by the archive, so that running the file extracts the archive and any ZIP reader can open it too.
A reader starts from the end of the file, so the stub does no harm in itself. The problem is the offsets. The offsets in the central directory and the end record count from the start of the archive, which is the start of the file only if nothing was added in front. A tool that writes the stub and then the archive may or may not add the stub’s size to every offset.
A reader works out which case it has by comparing where the central directory actually is with where the end record says:
actual = (start of the end record, or of the ZIP64 record) − directory size
shift = actual − directory offset stated in the end record
When shift is greater than zero, every stated offset must have
shift added to it. The explorer does this, and checks local headers to
tell a shifted archive from one whose end record is simply wrong.
Two more kinds of data can sit in gaps inside an archive:
- Android’s APK Signing Block sits between the last member’s data and the central directory, where ZIP readers do not look.
- Members that a tool has deleted can stay in the file after the directory is rewritten. Readers using the central directory do not see them.
Example
A complete archive of 128 bytes holding one stored file, hello.txt,
containing Hello, ZIP! and a newline. It was made with Info-ZIP’s
zip -X -0.
00000000 50 4B 03 04 0A 00 00 00 00 00 00 60 69 5D 0C 5D PK.........`i].]
00000010 86 8F 0C 00 00 00 0C 00 00 00 09 00 00 00 68 65 ..............he
00000020 6C 6C 6F 2E 74 78 74 48 65 6C 6C 6F 2C 20 5A 49 llo.txtHello, ZI
00000030 50 21 0A 50 4B 01 02 1E 03 0A 00 00 00 00 00 00 P!.PK...........
00000040 60 69 5D 0C 5D 86 8F 0C 00 00 00 0C 00 00 00 09 `i].]...........
00000050 00 00 00 00 00 00 00 00 00 00 00 A4 81 00 00 00 ................
00000060 00 68 65 6C 6C 6F 2E 74 78 74 50 4B 05 06 00 00 .hello.txtPK....
00000070 00 00 01 00 01 00 37 00 00 00 33 00 00 00 00 00 ......7...3.....
Read from the end: the end record at 0x6A says 1 member, a directory of
0x37 (55) bytes at 0x33, and no comment. The central header at
0x33 gives the name and the local header offset, 0. The local header at
0 has a name of 9 bytes and no extra field, so the data starts at 30 + 9 = 39
(0x27) and runs for 12 bytes.