Skip to content
AZ Tools

gzip (.gz) Inspector

A .gz file is not an archive. It is a stream: one or more members concatenated, each with its own 10-byte header, its own deflate stream and its own 8-byte trailer holding a CRC32 and ISIZE, the uncompressed length modulo 2^32. This page walks all of them and shows what every field actually says — the 1f 8b magic and the compression method, the five FLG bits (FTEXT, FHCRC, FEXTRA, FNAME, FCOMMENT) and which optional fields they promise, MTIME as a date, where 0 means it was never set and is what a reproducible build writes, XFL (2 for maximum compression, 4 for the fastest algorithm) and the OS byte by name, then the FEXTRA subfields split into their two-byte IDs and payloads, the original filename, the comment and the CRC16 header check. Then it verifies. Each member is inflated by the browser itself and its CRC32 recomputed over the result, so the trailer is checked instead of merely repeated: a file whose stored CRC32 does not match is corrupt in a way that otherwise surfaces halfway through a restore, long after the backup is gone. The same pass yields the real uncompressed size, which is why the total here can differ from gzip -l. gzip -l reads the last member’s ISIZE and reports it as the size of the whole file, so for anything built by cat a.gz b.gz, or by a parallel compressor such as pigz in independent-block mode, its answer is short by everything the earlier members hold. ISIZE is 32 bits wide, so a member larger than 4 GB stores its length modulo 2^32 and no reader can recover the true size from that field alone. Trailing garbage after the last trailer, a member that stops mid-stream and a file that is not gzip at all are each named rather than half-parsed. The filename inside the member — the name gunzip -N restores to, which can be a path or something entirely different from the file you are holding — is shown as stored; that field is ISO-8859-1 by specification but carries locale bytes in practice, so both readings appear whenever they differ.

How to use

  1. Drop a .gz, a .tgz or any gzip stream onto the box. It is parsed and inflated in the page; nothing is uploaded.
  2. Read the summary first: how many members the file really holds, the true uncompressed total, and whether every CRC32 matched.
  3. Open a member for its header — the five flag bits, MTIME, XFL, the OS byte, the stored filename, the comment and any FEXTRA subfields.
  4. Compare the two trailer pairs: CRC32 in trailer against CRC32 of the data, and ISIZE against the real uncompressed size. Two matches are exactly what gzip -t verifies.
  5. On a multi-member file, note the gap between the gzip -l figure and the true total before quoting a size that came from gzip -l.

Frequently asked questions

Why does gzip -l report a different size than this page?
Because gzip -l does not decompress anything. It seeks to the last four bytes of the file, reads that ISIZE and prints it as the uncompressed size. On a single-member file that is right. On a file made by concatenating members — cat a.gz b.gz, a rotated log appended to an archive, pigz or bgzip writing independent blocks — those four bytes describe only the final member, so gzip -l under-reports by the whole of everything before it. This page instead inflates every member and adds up what actually came out, which is why it can show a much larger total. It also means gzip -l is fast and this page is not: the cost of the honest answer is decompressing the file.
What does an MTIME of 0 mean, and what date does MTIME hold?
MTIME is the modification time of the original file, in seconds since the Unix epoch, UTC — not the time the compression ran, and not the timestamp of the .gz on disk. Zero means no time was available or none was stored: gzip -n writes 0 deliberately, and so do reproducible builds, because a timestamp is the classic reason two builds of identical content produce different bytes. Compressing from a pipe also gives 0, since there is no file to take a time from. The field is four bytes, so a date beyond 2106 cannot be represented at all, and implementations disagree about whether values above 2^31 are a far-future date or a negative one.
The original filename shows as mojibake. Is the file broken?
No — the format is. RFC 1952 says FNAME is an ISO-8859-1 (Latin-1) string, but gzip on Linux and macOS simply writes the bytes of the name as the local encoding produced them, which today is UTF-8. Anything outside ASCII therefore round-trips only between systems using the same encoding: a name written on a UTF-8 system and read as Latin-1 comes back as the familiar doubled accents. This page shows the field decoded as the spec demands and, when the same bytes are also valid UTF-8 and decode differently, the UTF-8 reading beside it — so you can see both candidate names and decide which one the writer meant.
What exactly does a CRC32 mismatch prove, and what does a match not prove?
A mismatch means the bytes that came out of the deflate stream are not the bytes that went in when the file was written: a flipped bit in storage, a truncated-then-patched transfer, an edit to the compressed data. It is the same failure gunzip reports as "invalid compressed data — crc error", except that here you see it without writing the output anywhere. A match only proves the data is what the compressor saw. CRC32 is a 32-bit error-detecting code, not a signature: it catches accidental damage with very high probability, but anyone who can change the data can also recompute the CRC. For authenticity you need a hash or a signature over the file, not its trailer.
Can this show the files inside a .tar.gz?
No, and nothing that reads only gzip can. gzip compresses one byte stream and knows nothing about what that stream contains — there is no table of contents, no per-file entry, no way to extract a single file without decompressing everything before it. A .tar.gz is a tar archive, which does have that structure, run through gzip as a whole. What this page can tell you is what the gzip layer records: how many members there are, the original filename in each header (often archive.tar), the timestamp and how much data comes out. To list the entries you need a tar reader working on the decompressed stream.
What are FEXTRA subfields used for?
FEXTRA is an extension point: a length-prefixed run of subfields, each a two-byte ID and its own length and payload, which a reader that does not recognise the ID must skip. Real uses are mostly about making a gzip stream seekable. BGZF, the format behind bgzip and every BAM file in genomics, writes a "BC" subfield giving the size of each block so a reader can jump straight to a block boundary; dictzip stores a chunk-length table under "RA" for the same reason. Both remain ordinary gzip files that gunzip reads normally, which is the point of the mechanism. A member with an unusual subfield is usually a hint that the file was written by such a tool.

Related tools