Why can't you combine .tar.gz files with cat?

speckx1 pts0 comments

Why can’t you combine .tar.gz files with cat? – alexwlchanSkip to main contentWhy can’t you combine .tar.gz files with cat?<br>Posted 20 August 2026<br>I’m working on a project that generates multiple .tar.gz archives, and I need to combine them into one final file. I thought I could just cat the bytes together, but that doesn’t work. This seemingly simple task exposed my flawed understanding of tar and gzip.<br>To my fix my code, I first had to fix my mental model – and that took me into tape drives, patent laws, and end-of-file markers.<br>tar stands for t ape ar chive<br>tar is a file archiver that combines multiple files and their metadata – filenames, timestamps, directory structure – into a single file.<br>It was originally designed for magnetic tapes, and the file structure is informed by the physical constraints of that medium:<br>Sequential reads. Magnetic tapes are most efficient when you start at the beginning, and play forward to the end of the tape.

Append-only writes. Early tapes could only append data to the end of a record, not replace existing data.

Fixed data sizes. Tapes have a fixed capacity, and early tapes had fixed data block sizes.

Internally, a tar archive is a sequence of files, each broken into fixed-size blocks. Files have a header block (with metadata like filename and file size) and data blocks (the file contents). After the files, there are two or more blocks filled entirely with zeroes. These form an end-of-file (EOF) marker that tells a reader to disregard everything else in the archive.<br>Architecture diagram showing the internals of a tar archive. There are two files with a header and data blocks, two blocks of zeroes, and two ignored blocks.headerdatadataheaderdatadatadatazeroeszeroesignoredignoredfile 1file 2EOF markerThis structure mirrors physical tape: you can read files sequentially or append new ones to the end. That sequential design is why tar remains popular for streaming over a network – you can process incoming files immediately, without waiting to download the complete archive.<br>Knowing this structure helps me understand aspects of tar that I previously found confusing:<br>File sizes must be declared upfront. You need to write the file size in the header before you write any data blocks. When I use Python’s TarFile.addfile API, I often forget to set tarinfo.size, so Python writes 0 to the header and creates an empty archive.

Archives can contain duplicate filenames. You can’t edit or delete existing blocks on tape, so you update a file by appending a new version with the same filename. When you unpack the archive, the later file overwrites the earlier one.

Everything after the EOF marker is ignored. Because physical tapes have fixed capacities, the EOF marker signals where data ends and empty tape begins. While tools like GNU tar have an --ignore-zeros flag to keep reading past EOF markers, I want to build archives that can be read with the default settings.

I tried a naïve approach of cat-ing tar archives, but that fails because readers stop at the first EOF marker. Instead, I’m combining archives using Python’s tarfile module. I unpack each archive, then copy its members into a new archive which will have a single EOF marker:<br>import tarfile

def combine_tars(output_file, input_files):<br>"""<br>Combine multiple tar archives into a single archive.<br>"""<br>with tarfile.open(output_file, "w") as out:<br>for f in input_files:<br>with tarfile.open(f, "r") as src:<br>for member in src.getmembers():<br>out.addfile(member, src.extractfile(member))

combine_tars("numbers.tar", ["one.tar", "two.tar", "three.tar"])This is more code than concatenating raw bytes, but it creates a tar archive that doesn’t need special settings to read.<br>gzip compresses a single stream of data<br>gzip is a stream compressor that takes a single file or data stream, and makes it smaller. The compression is lossless, so you can reverse it to retrieve the original file.<br>Unlike tar, gzip was a response to patent laws, not physical hardware. Reading RFC 1952 which defines the gzip file format, three design constraints reflect the time in which it was created:<br>Patent-free. The gzip tool was written as a free software replacement for compress, a comprssion tool whose underlying LZW algorithm was protected by patents at the time.

Streamable. Compressing or decompressing a gzip file must only use a small, bounded amount of memory. In the early 1990s, when RAM was even more scarce and expensive than it is today, the ability to process data in small, continuous chunks was essential.

Portable. A gzip file should be independent of the CPU, OS, filesystem, and other aspects of the computer it was created on. We take this sort of portability for granted today, but it wasn’t always a given.

Internally, a gzip file is a sequence of one or more “members”. Each member has a header (with metadata like original filename and modification time), the compressed data, and a trailer (with a CRC32 checksum and uncompressed size). The file ends after the final...

file data files archive gzip blocks

Related Articles