Как мне объединить много сжатых файлов в один архив?

10

У меня есть несколько сотен .tar.xzфайлов, которые почти идентичны (это ежедневные дампы базы данных, и база данных изменяется медленно).

Я полагаю, что из-за сходства несжатых файлов они будут очень хорошо сжиматься, и мелкомасштабные тесты показали, что сжатие любого количества этих несжатых файлов создает архив лишь немногим больше, чем один из них.

Моя проблема в том, что все несжатые файлы будут иметь размер несколько терабайт (степень сжатия составляет около 25: 1), и у меня не так много места на диске для использования в качестве рабочей области.

Можно ли обработать отдельные сжатые файлы по одному, добавив их в один архив и сохранив преимущества их сжатия?

jl6
источник
Вы пробовали написать его, чтобы распаковать один файл, добавить все файлы в определенный архив и затем перейти к следующему?
Дарнир

Ответы:

10

Поскольку tar-файлы являются потоковым форматом - вы можете catобъединить их два и получить почти правильный результат - вам вообще не нужно извлекать их на диск для этого. Вы можете распаковать (только) файлы, объединить их вместе и повторно сжать этот поток:

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

combined.tar.xzбудет сжатый архив всех файлов в компонентных архивах, который только слегка поврежден. Для извлечения вам придется использовать эту --ignore-zerosопцию (в GNU tar), потому что у архивов есть маркер «конца файла», который появится в середине результата. Кроме этого, все будет работать правильно.

GNU tarтакже поддерживает --concatenateрежим для создания комбинированных архивов. Это имеет те же ограничения, что и выше - вы должны использовать --ignore-zerosдля извлечения - но это не работает со сжатыми архивами. Вы можете создать что-то, чтобы обмануть это, используя подстановку процессов, но это хлопотно и даже более хрупко.

Если есть файлы, которые появляются в разных tar-файлах более одного раза, это не будет работать должным образом, но у вас есть проблема, независимо от того. В противном случае это даст вам то , что вы хотите - конвейерный вывод через xzто , как в tarлюбом случае сжимает свою продукцию.


Если архивы, которые работают только с определенной tarреализацией, не подходят для ваших целей, то добавление в архив с rвашим другом:

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

При этом извлекается только один архив за раз, поэтому рабочее пространство ограничено размером содержимого одного архива. Сжатие передается точно так же, как если бы вы сделали окончательный архив одновременно, так что оно будет таким же хорошим, как могло бы быть. Вы выполняете много лишних операций распаковки и повторного сжатия, которые будут делать это медленнее, чем catверсии, но полученный архив будет работать где угодно без какой-либо специальной поддержки.

Обратите внимание, что - в зависимости от того, что именно вы хотите - достаточно добавить сами несжатые tar-файлы в архив. Они будут сжимать (почти) точно так же, как и их содержимое в одном файле, и это уменьшит накладные расходы на сжатие для каждого файла. Это будет выглядеть примерно так:

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

Это немного менее эффективно с точки зрения окончательного сжатого размера, поскольку в потоке есть дополнительные заголовки tar, но экономит некоторое время на извлечение и повторное добавление всех файлов в виде файлов. В итоге вы получите combined.tar.xzмного (несжатых) db-*.tarфайлов.

Майкл Гомер
источник
Спасибо, ваш второй вариант выглядит правильным для моей цели, но не могли бы вы уточнить ваш последний абзац? Как это будет выглядеть?
JL6
@ JL6: см. редактировать.
Майкл Гомер
Извините, только что смог проверить это. Ваш второй метод дает мне эту ошибку:tar: Cannot update compressed archives
JL6