Crie e compare arquivos tar com Zstd e LZ4
Encaminhe a saída do tar por zstd ou lz4 para escolher explicitamente o compressor e suas configurações.
O passo a passo abaixo cria os dois arquivos compactados, restaura os arquivos contidos neles e mede
o tempo e o tamanho da compressão sobre a mesma entrada. Cada arquivo compactado só recebe um novo
nome depois que a compressão é concluída com sucesso; executar um comando novamente não pode
substituir um arquivo compactado existente.
Verifique suas ferramentas
Use Linux com Bash, GNU tar, GNU coreutils, diff, Python 3.9 ou mais recente, Zstd e LZ4 1.10.0 ou
mais recente. Os comandos abaixo foram testados com GNU tar 1.35, Bash 5.3.15, Zstd 1.5.7, LZ4 1.10.0
e Python 3.14.7. Instale as ferramentas ausentes pelo gerenciador de pacotes da sua distribuição e
depois verifique:
tar --version
bash --version
zstd --version
lz4 --version
python3 --version
ln --version
A implementação do tar faz diferença. O GNU tar suporta --zstd,
mas não tem a opção --lz4. O bsdtar suporta as duas opções ao criar arquivos tar
e detecta esses formatos ao lê-los. Este passo a passo usa o GNU tar e compressores separados; não é
uma receita de shell para macOS/BSD, sobretudo porque ln -T abaixo é uma opção do GNU.
Crie um diretório de origem reproduzível
Execute cada bloco Bash a partir do mesmo diretório inicial. Os parênteses mantêm cd e as opções do
shell locais a cada bloco. A preparação se recusa a reutilizar um diretório tar-lab existente, então não
pode sobrescrever um experimento anterior.
(
set -euo pipefail
mkdir tar-lab
cd -- tar-lab
mkdir project
python3 - <<'PY'
from pathlib import Path
import random
project = Path("project")
with (project / "records.csv").open("xb") as output:
for index in range(1_000_000):
output.write(f"{index:08d},user-{index % 1000:04d},GET,/assets/app.js,200\n".encode())
(project / "binary.bin").write_bytes(random.Random(0).randbytes(8 * 1024 * 1024))
(project / "empty.txt").touch()
(project / "omit.log").write_text("Exclude this log.\n", encoding="utf-8")
PY
)
Esses dados de teste combinam texto estruturado com bytes pseudoaleatórios determinísticos e um arquivo vazio. Mantenha a origem inalterada enquanto ela é arquivada. Um comando tar bem-sucedido não é um snapshot consistente de arquivos que uma aplicação está alterando ativamente.
Crie arquivos compactados sem substituir saídas anteriores
Os dois exemplos arquivam project/ e omitem nomes que correspondem a *.log, incluindo logs aninhados. O padrão
entre aspas chega ao tar sem expansão pelo shell. O -c do tar cria o arquivo tar; -f - o envia para
a saída padrão. O compressor grava em um diretório temporário novo ao lado do arquivo compactado
final, fora da árvore de origem.
pipefail faz o pipeline falhar quando o tar, que produz os dados, falha, mesmo que o compressor tenha
sucesso. Isso não protege um arquivo aberto por redirecionamento do shell: > pode truncar um backup
antigo antes de o tar ser executado. Aqui, apenas a saída temporária é redirecionada. Depois que o
teste de integridade do compressor passa, o ln -T do GNU dá a esses
bytes concluídos seu nome final. Sem -f, ele recusa um arquivo, diretório ou link simbólico existente.
Os nomes temporário e final ficam no mesmo sistema de arquivos, o que é exigido por links físicos. O
trap de saída remove o diretório temporário tanto em caso de sucesso normal quanto de falha.
Crie o arquivo compactado Zstd
Use o nível três e um worker de compressão. No
manual da CLI do Zstd, -T1 significa um
worker de compressão além do I/O; é diferente de --single-thread.
(
set -euo pipefail
cd -- tar-lab
stage=$(mktemp -d .zstd.XXXXXX)
trap 'rm -rf -- "$stage"' EXIT
tar --exclude='*.log' -cf - project | zstd -3 -T1 -c > "$stage/archive"
zstd -t "$stage/archive"
ln -T -- "$stage/archive" project.tar.zst
printf 'Created project.tar.zst\n'
)
Crie o arquivo compactado LZ4
Use também aqui o nível um e um worker de compressão. O LZ4 1.10.0 adicionou compressão multithread;
seu manual da CLI documenta -T1.
Versões mais antigas do LZ4 não suportam essa opção.
(
set -euo pipefail
cd -- tar-lab
stage=$(mktemp -d .lz4.XXXXXX)
trap 'rm -rf -- "$stage"' EXIT
tar --exclude='*.log' -cf - project | lz4 -1 -T1 -c > "$stage/archive"
lz4 -t "$stage/archive"
ln -T -- "$stage/archive" project.tar.lz4
printf 'Created project.tar.lz4\n'
)
Em caso de sucesso, o comando termina com a mensagem Created correspondente. Uma nova execução retorna um
status diferente de zero e deixa inalterados os bytes do arquivo compactado existente, mesmo que
project/ tenha desaparecido. Para criar outro arquivo compactado, escolha outro nome de arquivo final;
não remova um backup anterior só para fazer uma nova execução ter sucesso. Um kill forçado ou uma
queda de energia pode deixar arquivos temporários. Esses comandos não garantem durabilidade em caso
de falha do sistema.
Restaure e compare os arquivos
Um teste de integridade verifica o fluxo compactado, mas não comprova que ele contém os arquivos que você pretendia salvar. Restaure em um novo diretório e compare com a origem inalterada:
(
set -euo pipefail
cd -- tar-lab
zstd -t project.tar.zst
mkdir restored-zstd
zstd -dc project.tar.zst | tar -xf - -C restored-zstd
diff -r --exclude='*.log' project restored-zstd/project
printf 'Zstd restore matches the source.\n'
)
(
set -euo pipefail
cd -- tar-lab
lz4 -t project.tar.lz4
mkdir restored-lz4
lz4 -dc project.tar.lz4 | tar -xf - -C restored-lz4
diff -r --exclude='*.log' project restored-lz4/project
printf 'LZ4 restore matches the source.\n'
)
O esperado é nenhuma saída de diff e a mensagem de sucesso correspondente. As árvores restauradas contêm
records.csv, binary.bin e empty.txt; omit.log está ausente. Isso compara nomes e conteúdos de arquivos,
não proprietários, permissões ou todos os metadados do sistema de arquivos. Uma nova execução da
restauração recusa o diretório de restauração existente. Uma falha na extração pode deixar uma nova
árvore parcial, então só considere a restauração bem-sucedida depois que a comparação passar. Use
esses comandos para arquivos compactados que você criou e nos quais confia.
Meça as vantagens e desvantagens no mesmo fluxo tar
Execute este bloco a partir do diretório inicial depois da preparação. Ele cria um tar temporário sem compressão com ordem de membros, timestamps e propriedade fixos, e então mede cada compressor e decodificador. Há um aquecimento e cinco execuções medidas por codec. Cada tar decodificado precisa ser igual aos bytes de entrada. Apenas os arquivos temporários privados do benchmark são reutilizados; ele não mexe nos seus arquivos compactados nem nas suas restaurações.
python3 - <<'PY'
import hashlib
from pathlib import Path
from statistics import median
import subprocess
from tempfile import TemporaryDirectory
from time import perf_counter
def digest(path):
return hashlib.sha256(path.read_bytes()).digest()
def timed(command, source, destination):
with source.open("rb") as stdin, destination.open("wb") as stdout:
started = perf_counter()
subprocess.run(command, stdin=stdin, stdout=stdout, check=True)
return perf_counter() - started
with TemporaryDirectory(prefix="benchmark-", dir="tar-lab") as temporary:
work = Path(temporary)
raw = work / "input.tar"
with raw.open("xb") as output:
subprocess.run([
"tar", "--sort=name", "--mtime=@0", "--owner=0", "--group=0",
"--numeric-owner", "--exclude=*.log", "-cf", "-", "project",
], cwd="tar-lab", stdout=output, check=True)
expected = digest(raw)
raw_size = raw.stat().st_size
print(f"tar bytes: {raw_size}")
print("codec bytes compressed/tar compress_s decompress_s")
for codec, options in [("zstd", ["-3", "-T1"]), ("lz4", ["-1", "-T1"])]:
packed, decoded = work / codec, work / "decoded.tar"
samples = []
for run in range(6):
compress = timed([codec, *options, "-q", "-c"], raw, packed)
decompress = timed([codec, "-q", "-dc"], packed, decoded)
if digest(decoded) != expected:
raise RuntimeError(f"{codec} changed the tar bytes")
if run > 0:
samples.append((compress, decompress))
size = packed.stat().st_size
print(f"{codec} {size} {size / raw_size:.3f} "
f"{median(c for c, d in samples):.4f} {median(d for c, d in samples):.4f}")
PY
Os tempos incluem a inicialização de subprocessos e o I/O de arquivos locais, mas excluem a criação do tar, a extração de membros e a comparação SHA-256. São medições com cache aquecido, não um teste de throughput de disco. A razão é o número de bytes compactados dividido pelo número de bytes do tar sem compressão; quanto menor, melhor.
Em 24 de setembro de 2026, os dados de teste produziram um tar de 50.401.280 bytes no Linux x86-64 com uma CPU AMD Ryzen AI Max+ 395. Com as versões de ferramentas listadas acima, as medianas dos tempos decorridos foram:
| Configurações do compressor | Bytes do arquivo | Compactado/tar | Compressão | Descompressão |
|---|---|---|---|---|
Zstd -3 -T1 | 8.946.393 | 0,178 | 0,0281 s | 0,0124 s |
LZ4 -1 -T1 | 15.830.951 | 0,314 | 0,0519 s | 0,0332 s |
O Zstd produziu o arquivo compactado menor e concluiu as duas operações mais rápido nesta execução. A estrutura CSV repetida e os tempos de uma única máquina não estabelecem uma classificação universal. Substitua os dados de teste por arquivos representativos antes de escolher um compressor para sua carga de trabalho e verifique se o destinatário consegue decodificar o formato. Execuções curtas são sensíveis a outras atividades na máquina.
Use o resultado em um fluxo de trabalho de backup
Mantenha a compressão separada da seleção de arquivos e do histórico de backups. Selecionar arquivos
modificados recentemente com find não rastreia exclusões. Para uma cadeia de alterações restaurável,
siga o
passo a passo de backup incremental do GNU tar.
Agende um backup somente depois de testar seus caminhos de falha e de restauração, e mantenha os
arquivos compactados anteriores bem-sucedidos até que sua política de retenção permita removê-los.
Para transferências por SSH, copie um arquivo compactado concluído e verifique-o no destino. Se você dividir um arquivo compactado em partes, mantenha a ordem exata delas para a remontagem e verifique o arquivo remontado antes de restaurá-lo. Nem o transporte nem a divisão alteram a escolha do compressor medida aqui.
