Existe-t-il un moyen de convertir un zip en tar sans l'extraire dans le système de fichiers?

17

Existe-t-il un moyen de convertir une ziparchive en tararchive sans extraire au préalable dans un répertoire temporaire? (et sans écrire ma propre implémentation de tarou unzip)

user253751
la source
Considérez-vous le montage de l'archive zip comme une extraction vers le système de fichiers? Si oui, alors vous pouvez le faire sans rien extraire avec libarchive mais cela implique un codage.
Celada
Je pense que l'op cherche quelque chose comme ça superuser.com/questions/325504/… est-ce le genre de chose que vous espérez réaliser?
vfbsilva

Réponses:

12

Ceci est maintenant disponible en tant que commande installable de PyPI, voir la fin de ce post.


Je ne connais aucun utilitaire "standard" qui le fasse, mais quand j'ai eu besoin de cette fonctionnalité, j'ai écrit le script Python suivant pour passer de ZIP aux archives tar compressées Bzip2 sans extraire quoi que ce soit sur le disque d'abord:

#! /usr/bin/env python

"""zip2tar """

import sys
import os
from zipfile import ZipFile
import tarfile
import time

def main(ifn, ofn):
    with ZipFile(ifn) as zipf:
        with tarfile.open(ofn, 'w:bz2') as tarf:
            for zip_info in zipf.infolist():
                #print zip_info.filename, zip_info.file_size
                tar_info = tarfile.TarInfo(name=zip_info.filename)
                tar_info.size = zip_info.file_size
                tar_info.mtime = time.mktime(list(zip_info.date_time) +
                                         [-1, -1, -1])
                tarf.addfile(
                    tarinfo=tar_info,
                    fileobj=zipf.open(zip_info.filename)
                )

input_file_name = sys.argv[1]
output_file_name = os.path.splitext(input_file_name)[0] + '.tar.bz2'

main(input_file_name, output_file_name)

Il suffit de l'enregistrer zip2taret de le rendre exécutable ou de l'enregistrer zip2tar.pyet de l'exécuter python zip2tar.py. Fournissez le nom de fichier ZIP comme argument au script, le nom de fichier de sortie pour xyz.zipsera xyz.tar.bz2.

La sortie compressée Bzip2 est normalement beaucoup plus petite que le fichier zip car ce dernier n'utilise pas de modèles de compression sur plusieurs fichiers, mais il y a également moins de chances de récupérer un fichier ultérieur si quelque chose dans le fichier Bzip2 est incorrect.

Si vous ne voulez pas que la sortie soit compressée, supprimez :bz2et .bz2du code.


Si vous avez pipinstallé dans un environnement python3, vous pouvez faire:

pip3 install ruamel.zip2tar

pour obtenir un zip2tarutilitaire de ligne de commande faisant ce qui précède (avertissement: je suis l'auteur de ce package).

Anthon
la source
1
Joli. Il semble que le script n'essaie pas de copier des métadonnées telles que l'heure de modification du fichier et les autorisations lors du changement de format d'archive, mais je pense que vous pourriez l'ajouter assez facilement.
Celada
@Celada J'ai ajouté l'heure de modification du fichier (j'ai raté cela pendant que je copiais et collais à partir de mon code d'origine), je ne sais pas si la norme ZIP a réellement des autorisations, AFAIK (moderne) tar est plus complet à cet égard, ZIP plus orienté Windows .
Anthon
Exactement ce que je cherchais. Je m'attendais à ce qu'un utilitaire comme celui-ci soit disponible à partir des packages Unix standard. Quelle est la licence de cela? J'aimerais proposer qu'il soit inclus dans certains paquets (par exemple, les devutils de Debian), peut-être après quelques généralisations.
rbrito
Autre commentaire: la référence à timemanque un import.
rbrito
@rbrito Je posterai ceci sur PyPI, n'importe quelle distribution peut le récupérer à partir de là. Tout comme certains le font avec mon package ruamel.yaml. Merci pour le timecommentaire, je mets à jour la réponse
Anthon
5

La tarcommande traite des systèmes de fichiers. Son entrée est une liste de fichiers qu'il lit ensuite à partir d'un système de fichiers (y compris un grand nombre de métadonnées). Vous devrez présenter le fichier zip comme un système de fichiers pour que la tarcommande le lise.

Un système de fichiers virtuel - AVFS permettra à tout programme de regarder à l'intérieur des fichiers archivés ou compressés via une interface de système de fichiers standard via FUSE .

Il y a des informations détaillées dans le fichier Lisezmoi d'avfs-fuse et certaines distributions ont packages pour cela.

Un que vous avez installé AVFS, alors vous pouvez

mountavfs
cd ~/.avfs/path/to/somefile.zip#
tar -cvf /path/whatever.tar .

AVFS remplira toutes les informations du système de fichiers manquantes dans le zip, comme la propriété du fichier, que tar récupérera.

Mat
la source
0

Voici un petit extrait qui convertit une archive ZIP en une archive TAR.GZ correspondante OnTheFly.

Conversion d'archive ZIP en archive TAR à la volée

# File: zip2tar.py
#
# Convert ZIP archive to TAR.GZ archive.
#
# Written by Fredrik Lundh, March 2005.

# helpers (tweak as necessary)

def getuser():
    # return user name and user id
    return "anonymous", 1000

def getmode(name, data):
    # return mode ("b" or "t") for the given file.
    # you can do this either by inspecting the name, or
    # the actual data (e.g. by looking for non-ascii, non-
    # line-feed data).
    return "t" # assume everything's text, for now

#
# main

import tarfile
import zipfile

import glob, os, StringIO, sys, time

now = time.time()

user = getuser()

def fixup(infile):

    file, ext = os.path.splitext(infile)

    outfile = file + ".tar.gz"
    dirname = os.path.basename(file)

    print outfile

    zip = zipfile.ZipFile(infile, "r")

    tar = tarfile.open(outfile, "w:gz")
    tar.posix = 1

    for name in zip.namelist():

        if name.endswith("/"):
            continue

        data = zip.read(name)
        if getmode(name, data) == "t":
            data = data.replace("\r\n", "\n")

        tarinfo = tarfile.TarInfo()
        tarinfo.name = name
        tarinfo.size = len(data)
        tarinfo.mtime = now
        tarinfo.uname = tarinfo.gname = user[0]
        tarinfo.uid = tarinfo.gid = user[1]
        tar.addfile(tarinfo, StringIO.StringIO(data))

    tar.close()
    zip.close()

# convert all ZIP files in the current directory
for file in glob.glob("*.zip"):
    fixup(file)

La source

Evgeni Braverman
la source