Existe uma maneira de converter um zip em um alcatrão sem extraí-lo para o sistema de arquivos?

17

Existe uma maneira de converter um ziparquivo em um tararquivo sem extrair primeiro um diretório temporário? (e sem escrever minha própria implementação de tarou unzip)

user253751
fonte
Você conta como montar o arquivo zip como extraí-lo no sistema de arquivos? Se sim, você pode fazê-lo sem extrair nada com libarchive, mas isso envolve codificação.
Celada
Acho que o op procura algo como esse superuser.com/questions/325504/…, é o tipo de coisa que você espera alcançar?
vfbsilva

Respostas:

12

Agora está disponível como comando instalável do PyPI, consulte o final deste post.


Não conheço nenhum utilitário "padrão" que o faça, mas quando precisei dessa funcionalidade, escrevi o seguinte script Python para ir dos arquivos tar compactados ZIP para Bzip2 sem extrair nada para o disco primeiro:

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

Apenas salve-o zip2tare torne-o executável ou salve-o zip2tar.pye execute-o python zip2tar.py. Forneça o nome do arquivo ZIP como argumento para o script, o nome do arquivo de saída xyz.zipserá xyz.tar.bz2.

A saída compactada do Bzip2 é normalmente muito menor que o arquivo zip, porque este último não usa padrões de compactação em vários arquivos, mas também há menos chances de recuperar arquivos posteriores se algo no arquivo Bzip2 estiver errado.

Se você não deseja compactar a saída, remova :bz2e .bz2do código.


Se você pipinstalou em um ambiente python3, pode:

pip3 install ruamel.zip2tar

para obter um zip2tarutilitário de linha de comando fazendo o acima (aviso: eu sou o autor desse pacote).

Anthon
fonte
1
Agradável. Parece que o script não faz nenhuma tentativa de copiar metadados, como o tempo de modificação do arquivo e as permissões na alteração do formato do arquivo, mas acho que você pode adicionar isso facilmente.
Celada
@Celada Adicionei o tempo de modificação do arquivo (perdi isso ao copiar e colar do meu código original), não tenho certeza se o padrão ZIP realmente tem permissões, o tar AFAIK (moderno) é mais completo nesse sentido, pois o ZIP é mais orientado para o Windows .
Anthon
Exatamente o que eu estava procurando. Eu esperava que um utilitário como este estivesse disponível em pacotes unix padrão. Qual é a licença disso? Eu gostaria de propor que ele fosse incluído em alguns pacotes (por exemplo, devutils do Debian), talvez após algumas generalizações.
Rbrito 01/07
Outro comentário: a referência a timefalta de um import.
Rbrito 01/07
@rbrito Vou postar isso no PyPI, qualquer distro pode pegá-lo a partir daí. Assim como alguns fazem com o meu pacote ruamel.yaml. Obrigado pelo timecomentário, eu atualizar a resposta
Anthon
5

O tarcomando lida com sistemas de arquivos. Sua entrada é uma lista de arquivos que são lidos em um sistema de arquivos (incluindo muitos metadados). Você precisaria apresentar o arquivo zip como um sistema de arquivos para o tarcomando lê-lo.

Um sistema de arquivos virtual - AVFS permitirá que qualquer programa procure dentro de arquivos compactados ou arquivados por meio de uma interface padrão de sistema de arquivos via FUSE .

Há algumas informações detalhadas no leia-me do avfs-fuse e algumas distribuições têm pacotes para isso.

Se você tiver o AVFS instalado, poderá

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

O AVFS preencherá todas as informações do sistema de arquivos ausentes do zip, como a propriedade do arquivo, que o tar será capturado.

Matt
fonte
0

Aqui está um pequeno trecho que converte um arquivo ZIP em um arquivo TAR.GZ correspondente no OnTheFly.

Converter arquivo ZIP em arquivo TAR em tempo real

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

Fonte

Evgeni Braverman
fonte