Como devo combinar muitos arquivos compactados em um único arquivo?

10

Eu tenho alguns arquivos cem .tar.xz que são quase idênticos (eles são despejos de banco de dados diários e o banco de dados muda lentamente).

Acredito que, devido às semelhanças nos arquivos descompactados, eles serão compactados muito bem, e testes de pequena escala mostraram que a compactação de qualquer número desses arquivos descompactados cria um arquivo apenas um pouco maior que um deles.

Meu problema é que todos os arquivos descompactados teriam alguns terabytes (a taxa de compactação é de cerca de 25: 1) e eu não tenho muito espaço em disco para usar como área de trabalho.

Existe uma maneira de processar os arquivos compactados individuais, um por vez, adicionando-os a um único arquivo e retendo os benefícios de compactá-los juntos?

    
por jl6 22.08.2014 / 18:43

1 resposta

9

Como os arquivos tar são um formato de streaming - você pode usar cat dois juntos e obter um resultado quase correto - você não precisa extraí-los para o disco para fazer isso. Você pode descompactar (apenas) os arquivos, concatená-los juntos e recompactar esse fluxo:

xzcat *.tar.xz | xz -c > combined.tar.xz

combined.tar.xz será um tarball compactado de todos os arquivos nos tarballs do componente que está apenas um pouco corrompido. Para extrair, você terá que usar a --ignore-zeros opção (no GNU tar ), porque os arquivos têm um marcador de "fim-de-arquivo" que aparecerá no meio do resultado. Além disso, tudo funcionará corretamente.

O GNU tar também suporta um modo --concatenate para produzir arquivos combinados . Isso tem as mesmas limitações acima - você deve usar --ignore-zeros para extrair - mas não funciona com arquivos compactados. Você pode construir algo para transformá-lo em trabalho usando a substituição de processos, mas é um aborrecimento e ainda mais frágil.

Se houver arquivos que aparecem mais de uma vez em arquivos tar diferentes, isso não funcionará corretamente, mas você tem esse problema, independentemente disso. Caso contrário, isso fornecerá o que você deseja - canalizar a saída por meio de xz é como tar compacta sua saída de qualquer maneira.

Se os arquivos que só funcionam com uma implementação tar em particular não forem adequados para seus propósitos, anexar ao arquivo com r é seu amigo:

tar cJf combined.tar.xz dummy-file
for x in db-*.tar.xz
do
    mkdir tmp
    pushd tmp
    tar xJf "../$x"
    tar rJf ../combined.tar.xz .
    popd
    rm -r tmp
done

Isso só extrai um único arquivo por vez, portanto, o espaço de trabalho é limitado ao tamanho do conteúdo de um único arquivo. A compressão está fluindo como se você tivesse feito o arquivo final de uma só vez, então será tão bom quanto poderia ter sido. Você faz um monte de descompactação e recompressão em excesso que tornarão isso mais lento que as versões cat , mas o arquivo resultante funcionará em qualquer lugar sem qualquer suporte especial.

Observe que - dependendo do que exatamente você quer - apenas adicionar os arquivos tar descomprimidos a um arquivo morto pode ser suficiente. Eles compactarão (quase) exatamente o mesmo que seu conteúdo em um único arquivo e reduzirá a sobrecarga de compactação para cada arquivo. Isso seria algo como:

tar cJf combined.tar.xz dummy-file
for x in db-*.tar.xz
do
    xz -dk "$x"
    tar rJf combined.tar.xz "${x%.xz}"
    rm -f "${x%.xz}"
done

Isso é um pouco menos eficiente em termos do tamanho final compactado, porque há cabeçalhos extras de tar no fluxo, mas economiza algum tempo na extração e re-adição de todos os arquivos como arquivos. Você acabaria com combined.tar.xz contendo muitos arquivos db-*.tar (não compactados).

    
por 23.08.2014 / 01:10