¿Hay alguna manera de convertir un zip en un tar sin extraerlo al sistema de archivos?

17

¿Hay alguna manera de convertir un ziparchivo en un tararchivo sin extraerlo primero a un directorio temporal? (y sin escribir mi propia implementación de taro unzip)

usuario253751
fuente
¿Considera montar el archivo zip como extraerlo al sistema de archivos? En caso afirmativo, puede hacerlo sin extraer nada con libarchive, pero eso implica la codificación.
Celada
Creo que el operador busca algo como este superuser.com/questions/325504/… ¿ es el tipo de cosas que esperas lograr?
vfbsilva

Respuestas:

12

Ahora está disponible como comando instalable desde PyPI, vea el final de esta publicación.


No conozco ninguna utilidad "estándar" que lo haga, pero cuando necesitaba esta funcionalidad, escribí el siguiente script de Python para pasar de archivos comprimidos tar a ZIP a Bzip2 sin extraer nada al disco primero:

#! /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)

Simplemente guárdelo zip2tary hágalo ejecutable o guárdelo zip2tar.pyy ejecútelo python zip2tar.py. Proporcione el nombre de archivo ZIP como argumento para el script, el nombre de archivo de salida xyz.zipserá xyz.tar.bz2.

La salida comprimida de Bzip2 normalmente es mucho más pequeña que el archivo zip porque este último no usa patrones de compresión en varios archivos, pero también hay menos posibilidades de recuperar el archivo posterior si algo en el archivo Bzip2 está mal.

Si no desea comprimir la salida, elimine :bz2y .bz2del código.


Si ha pipinstalado en un entorno python3, puede hacer:

pip3 install ruamel.zip2tar

para obtener una zip2tarutilidad de línea de comandos haciendo lo anterior (descargo de responsabilidad: soy el autor de ese paquete).

Anthon
fuente
1
Buena esa. Parece que el script no hace ningún intento de copiar metadatos, como el tiempo de modificación del archivo y los permisos a través del cambio de formato del archivo, pero creo que podría agregarlo con bastante facilidad.
Celada
@Celada Agregué el tiempo de modificación del archivo (se me olvidó que al copiar y pegar desde mi código original), no estoy seguro de si el estándar ZIP realmente tiene permisos, el alquitrán AFAIK (moderno) es más completo en ese sentido con ZIP más orientado a Windows .
Anthon
Exactamente lo que estaba buscando. Esperaba que una utilidad como esta estuviera disponible en los paquetes estándar de Unix. ¿Cuál es la licencia de esto? Me gustaría proponer que se incluya en algunos paquetes (por ejemplo, los devutils de Debian), tal vez después de algunas generalizaciones.
rbrito 01 de
Otro comentario: la referencia a timecarece de un import.
rbrito 01 de
@rbrito Voy a publicar esto en PyPI, cualquier distribución puede recogerlo desde allí. Al igual que algunos hacen con mi paquete ruamel.yaml. Gracias por el timecomentario, actualizo la respuesta
Anthon
5

El tarcomando trata con los sistemas de archivos. Su entrada es una lista de archivos que luego lee de un sistema de archivos (incluidos muchos metadatos). Debería presentar el archivo zip como un sistema de archivos para que el tarcomando lo lea.

Un sistema de archivos virtual: AVFS permitirá que cualquier programa busque archivos comprimidos o comprimidos a través de una interfaz de sistema de archivos estándar a través de FUSE .

Hay información detallada en el archivo Léame avfs-fuse y algunas distribuciones tienen paquetes para ello.

Uno tiene instalado AVFS, luego puede

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

AVFS completará cualquier información para el sistema de archivos que falta en el archivo zip, como la propiedad del archivo, que recogerá tar.

Mate
fuente
0

Aquí hay un pequeño fragmento que convierte un archivo ZIP en un archivo TAR.GZ coincidente en OnTheFly.

Convierte archivos ZIP a archivos TAR sobre la marcha

# 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)

Fuente

Evgeni Braverman
fuente