Comment recompresser 2 millions de fichiers gzip sans les stocker deux fois?

8

J'ai environ 2 millions (60 Go) de petits fichiers compressés et je voudrais créer une archive compressée les contenant tous dans une version non compressée. Malheureusement, je ne peux pas tous les décompresser, puis créer l'archive compressée car je n'ai que 70 Go d'espace disque libre. En d'autres termes, comment puis-je faire un équivalent de tar --file-filter="zcat" zcf file.tar.gz directorysi le commutateur de ligne de commande comme --file-filtern'existe pas dans GNU tar?

d33tah
la source
Avez-vous une machine multiprocesseur?
Anthon
1
@Anthon: pas sur cette machine, mais pour les futurs lecteurs, nous pourrions supposer que oui.
d33tah
Comme vous devez recompresser, il y a quelque chose à y gagner. Une raison particulière pour laquelle utiliser gzip? La combinaison et la compression économisent de l'espace, mais vous gagneriez beaucoup plus si vous compressiez dans un xzfichier tar -ed. Est-ce une option?
Anthon
N'importe quel programme de compression ferait l'affaire. Si je peux créer un fichier tar des fichiers décompressés mais non stockés, je peux le diriger vers n'importe quel autre programme.
d33tah

Réponses:

6

Une option pourrait être d'utiliser avfs(en supposant ici un système GNU):

mkdir ~/AVFS &&
avfsd ~/AVFS &&
cd ~/AVFS/where/your/gz/files/are/ &&
find . -name '*.gz' -type f -printf '%p#\0' |
  tar --null -T - --transform='s/.gz#$//' -cf - | pigz > /dest/file.tar.gz
Stéphane Chazelas
la source
3

Notez que cela est fragile en ce qui concerne les noms de fichiers désagréables.

dir_with_small_files=/home/john/files
tmpdir=/tmp/ul/dst
tarfile=/tmp/ul.tar
mkfifo "${tarfile}"

gzip <"${tarfile}" >"${tarfile}.gz" &

find "$dir_with_small_files" -type f | \
while read src; do
    dstdir="${tmpdir}/$(dirname $src)"
    dst="$(basename $src .gz)"
    mkdir -p "$dstdir"
    gunzip <"$src" >"${dstdir}/${dst}"
    # rm "$src" # uncomment to remove the original files
    echo "${dstdir}/${dst}"
done | \
cpio --create --format=ustar -v --quiet 2>&1 >"${tarfile}" | \
while read x; do
    rm "$x"
done

# clean-up
rm "$tarfile"
rm -r "$tmpdir"

Les fichiers sont décompressés temporairement sous $tmpdir, passés à cpiopuis dès qu'ils sont ajoutés à l'archive, supprimés.

Cristian Ciupitu
la source
1
De plus, si vous avez plusieurs threads, je suggère d'utiliser pigzune alternative à gzip :)
Christopher Stanley
2

Voici ce que j'ai essayé jusqu'à présent - cela semble fonctionner, mais il est terriblement lent, même avec PyPy:

#!/usr/bin/python

import tarfile
import os
import gzip
import sys
import cStringIO

tar = tarfile.open("/dev/stdout", "w|")
for name in sys.stdin:
    name = name[:-1]  # remove the trailing newline
    try:
        f = gzip.open(name)
        b = f.read()
        f.close()
    except IOError:
        f = open(name)
        b = f.read()
        f.close()
    # the [2:] there is to remove ./ from "find" output
    ti = tarfile.TarInfo(name[2:])
    ti.size = len(b)
    io = cStringIO.StringIO(b)
    tar.addfile(ti, io)
tar.close()

Usage: find . | script.py | gzip > file.tar.gz

d33tah
la source
La décompression et surtout la recompression sur un disque presque plein va être lente quoi qu'il arrive.
Cristian Ciupitu
@CristianCiupitu: J'ai mesuré sans |gzipet le fichier non compressé n'a pas fondamentalement touché le disque dur, donc à mon humble avis , cela ne devrait pas être TELLEMENT lent.
d33tah
1
La décompression et la décompression sont effectuées en code C optimisé dans CPython. Il peut y avoir une mise en mémoire tampon qui empêche le disque de toucher.
Anthon
1
trouver . -exec cat \ {\} \; > / dev / null devrait fournir une limite inférieure sur le temps que cette opération pourrait éventuellement prendre. J'imagine qu'une partie de votre problème est la création d'un tas de gros objets python contenant vos fichiers sous des formes compressées et non compressées, puis en laissant le garbage collector se nettoyer après vous-même. voir ici: stackoverflow.com/questions/6115066/…
BitShifter
Vous pourriez probablement économiser de la mémoire en déterminant la taille non compressée et en la transmettant au tarfichier gzip comme un objet.
Cristian Ciupitu