The end of central directory record comes last in the file and tells a reader how many members there are and where the central directory is. Every archive has exactly one. An archive holding only this record is empty and valid.
Fields
| Offset | Size | Name | Description |
|---|---|---|---|
0 | 4 | Signature | 50 4B 05 06, the value 0x06054B50. |
4 | 2 | Disk number | The number of the disk this record is on. 0xFFFF if in the ZIP64 end record. |
6 | 2 | Directory disk | The disk the central directory starts on. 0xFFFF if in the ZIP64 end record. |
8 | 2 | Entries on this disk | The number of central directory entries on this disk. 0xFFFF if in the ZIP64 end record. |
10 | 2 | Total entries | The total number of central directory entries. 0xFFFF if in the ZIP64 end record. |
12 | 4 | Directory size | The size of the central directory in bytes. 0xFFFFFFFF if in the ZIP64 end record. |
16 | 4 | Directory offset | The offset of the start of the central directory, on the disk where it starts. 0xFFFFFFFF if in the ZIP64 end record. May need shifting. |
20 | 2 | Comment length | The length of the archive comment. |
22 | comment length | Comment | The archive comment. Stored as is, with no encryption. |
In a single-file archive, both disk numbers are 0 and the two entry counts are equal. The end record and the ZIP64 locator must be on the same disk when an archive is split. For the case where any field overflows, see the sentinels.
The smallest archive is the 22-byte record with all other bytes zero:
00000000 50 4B 05 06 00 00 00 00 00 00 00 00 00 00 00 00 PK..............
00000010 00 00 00 00 00 00 ......
Finding the record
There is no pointer to it, and its comment can be up to 65,535 bytes long, so the record starts somewhere in the last 22 + 65,535 = 65,557 bytes of the file. A reader searches backwards:
- If the file is shorter than 22 bytes, it is not a ZIP archive.
- Read the last 65,557 bytes, or the whole file if it is shorter.
- From the position 22 bytes before the end, step backwards one byte at a time looking
for
50 4B 05 06. - At each match, read the comment length at offset 20 and accept the record if the comment ends at the end of the file.
- Continue until a match is accepted or the search area is used up. Checking the central directory next, as below, confirms the find.
The fast case is common and worth testing first: if the last 22 bytes start with the
signature and end with a zero comment length, the record is there and no search is
needed. Python’s zipfile does this, then falls back to a search for the last
signature in the final 65,557 bytes.
The comment problem
Nothing stops a comment from containing the bytes 50 4B 05 06. If a comment
ends with bytes that look like a complete empty end record, a search from the end finds
the fake record first. A reader that takes the last match in the file then sees a
different archive from a reader that takes the first match, or that checks more than one
candidate.
Trailing bytes after the archive cause the opposite problem. A file that has been appended to, or padded by a transfer, has no match whose comment ends at the end of the file. Readers then either fail or accept a record whose comment fits within the file.
To handle both:
- Prefer a candidate whose comment ends exactly at the end of the file. The explorer does this first.
- If there is none, accept the last candidate whose comment fits within the file, and report that the file has trailing data. The explorer does this as its fallback.
- Validate the candidate: the offset and size must point to a
50 4B 01 02record, or to the exact end of the data for an empty archive. A false match fails this check and the search continues.
A writer should not put the end record’s signature in a comment. The reading and writing page covers how different readers handle these cases.