Memra

Three transforms that are not each other

◈ 9 cards

Compression, encoding and encryption compared on what they change, what undoes them and whether they keep a secret; archiving a directory with tar; and why a binary you must e-mail is compressed before it is encoded.

Three transforms, routinely confused

Students merge these three because all of them turn a file into a different-looking file. They are not variations on a theme; they answer three different questions.

Compression changes the representation. The information is identical; the encoding of it is shorter. Lossless compression — gzip, compress, zip — recovers the original byte for byte, and it is the only kind you may use on text, source code or an executable. Lossy compression — JPEG, MP3 — discards information you are betting nobody will miss, and applying it to a program produces a program that does not run. Compression buys disk space and transmission time and pays for them in CPU time, which is a good trade whenever the file will be sent more than once.

Encoding changes the alphabet. It takes arbitrary bytes and re-expresses them using only printable characters, because some transport in the middle — classically e-mail, which was defined for seven-bit text — cannot carry arbitrary bytes. It is fully reversible by anyone, needs no key, and makes the file bigger: base64 inflates by about 33%, and the older uuencode by about 38% once its line framing is counted.

Encryption changes the content under a key. It is reversible only by someone holding the key, and it is the only one of the three that keeps a secret. It does not shrink anything; done well, ciphertext is statistically indistinguishable from random bytes, which is exactly why it does not compress afterwards.

Compression ratio is a property of the file, not the tool

Run gzip -9 — maximum effort — over three files and the results are nothing like each other:

$ gzip -9 access.log report.txt photo.jpg
$ gzip -l access.log.gz report.txt.gz photo.jpg.gz
 compressed  uncompressed  ratio  uncompressed_name
     181203       2612094  93.1%  access.log
     139560        436124  68.0%  report.txt
    1904118       1911774   0.4%  photo.jpg

The log is 93% smaller because it is thousands of near-identical lines and a compressor's whole business is repetition. The plain-text report loses about two thirds, which is typical for English prose. The JPEG barely moves, because JPEG is compression — the redundancy was already spent, and there is nothing left for gzip to find. Compressing an already-compressed file is at best free and often slightly negative.

The commands themselves are short. gzip file writes file.gz and deletes the original; gunzip file.gz reverses it; -1 through -9 trade speed for ratio; -l lists the sizes and ratio without decompressing; zcat file.gz writes the decompressed contents to standard output, leaving the archive alone, so it composes into a pipeline. The classic compress/uncompress pair behaves the same way with a .Z suffix and an older algorithm.

Archiving: tar

gzip compresses one file. To package a whole directory you first need to turn the directory into a single stream, and that is what tar — tape archive — does. It is universally paired with a compressor, and GNU tar will drive one for you with a single option letter:

$ tar -czf proj.tar.gz proj
$ tar -tzf proj.tar.gz
proj/
proj/alpha.txt
proj/.hidden
proj/src/
proj/src/main.c
$ mkdir -p /tmp/restore
$ tar -xzf proj.tar.gz -C /tmp/restore

Read the option letters as three independent choices. Exactly one of c (create), t (list) or x (extract) says what you are doing. z says the stream passes through gzip on the way — that is the letter doing the compression, and dropping it on extraction of a .tar.gz is the most common tar mistake there is. f says the next argument is the archive filename rather than a tape device. -C dir changes directory before extracting, which is how you restore somewhere other than where you are standing.

Two things tar does that the glob-based commands of the last lesson do not: it includes dotfiles, because it walks the directory itself rather than being handed an expansion, and it preserves the tree — permissions, modification times and the directory structure all come back on extraction.

Worked example — getting a binary through a text-only channel

You must send a 4 MB executable through something that accepts only printable text. Two transforms are needed, and their order is not a matter of taste.

Compress first, then encode. Compression on the original gets whatever ratio the content allows — call it 60%, leaving 1.6 MB — and encoding then inflates that by a third, to about 2.1 MB. Do it the other way and encoding inflates 4 MB to 5.3 MB, and compressing that recovers very little: base64 output is a near-uniform stream of 64 characters, with the file's original redundancy already smeared across it. You end up with a much larger message and more CPU spent producing it.

$ gzip -9 tool.bin
$ base64 tool.bin.gz > tool.b64

The inverse pipeline is the exact mirror, decode then decompress:

$ base64 -d tool.b64 > tool.bin.gz
$ gunzip tool.bin.gz

The general rule, and it is worth carrying past this course: compress before you encode, and compress before you encrypt. Both encoding and encryption destroy the redundancy that a compressor lives on, so anything applied after them compresses badly or not at all.

TransformWhat it changesUndo without asecret?Provides secrecy?compressionthe representation— smalleryesnoencodingthe alphabet —about 33% largeryesnoencryptionthe content, undera keyno — needs the keyyesCompress first: encoding and encryption both destroy redundancy.
Only one of the three keeps a secret, and only one of the three makes the file bigger. Getting those two facts the right way round is most of what this lesson is for.

source GNU tar manual §2-3; POSIX.1-2024 pax

source GNU tar manual §2-3; POSIX.1-2024 pax

source GNU tar manual §2-3; POSIX.1-2024 pax

NORMAL ~/memra/learn/comp-325/compression-encoding-encryption-and-tar utf-8 LF