Gibt es eine Möglichkeit, eine Zip-Datei in eine Teer-Datei umzuwandeln, ohne sie in das Dateisystem zu extrahieren?

17

Gibt es eine Möglichkeit, ein zipArchiv in ein tarArchiv zu konvertieren , ohne es zuerst in ein temporäres Verzeichnis zu extrahieren? (und ohne meine eigene Implementierung von taroder zu schreiben unzip)

user253751
quelle
Zählen Sie das Mounten des Zip-Archivs zum Extrahieren in das Dateisystem? Wenn ja, dann können Sie es tun, ohne etwas mit libarchive zu extrahieren, aber das beinhaltet Codierung.
Celada
Ich denke, die Operation sieht nach so etwas aus. Superuser.com/questions/325504/… ist es das, was Sie sich erhoffen?
Vfbsilva

Antworten:

12

Dies ist jetzt als installierbarer Befehl von PyPI verfügbar (siehe Ende dieses Beitrags).


Ich kenne kein "Standard" -Dienstprogramm, das dies tut, aber als ich diese Funktionalität benötigte, schrieb ich das folgende Python-Skript, um von ZIP zu Bzip2-komprimierten Tar-Archiven zu wechseln, ohne zuerst etwas auf die Festplatte zu extrahieren:

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

Einfach speichern zip2tarund ausführbar machen oder speichern zip2tar.pyund ausführen python zip2tar.py. Geben Sie den ZIP-Dateinamen als Argument für das Skript an. Der Ausgabedateiname für xyz.ziplautet xyz.tar.bz2.

Die komprimierte Ausgabe von Bzip2 ist normalerweise viel kleiner als die ZIP-Datei, da letztere keine Komprimierungsmuster für mehrere Dateien verwendet, aber es besteht auch eine geringere Wahrscheinlichkeit, dass eine spätere Datei wiederhergestellt wird, wenn etwas in der Bzip2-Datei nicht stimmt.

Wenn Sie die Ausgabe nicht komprimieren möchten, entfernen Sie :bz2und .bz2aus dem Code.


Wenn Sie pipin einer python3-Umgebung installiert haben , können Sie Folgendes tun:

pip3 install ruamel.zip2tar

Um ein zip2tarKommandozeilen-Dienstprogramm zu erhalten, das die oben genannten Schritte ausführt (Haftungsausschluss: Ich bin der Autor dieses Pakets).

Anthon
quelle
1
Schön. Es sieht so aus, als würde das Skript nicht versuchen, Metadaten wie Änderungszeit und Berechtigungen für das Archivformat zu kopieren, aber ich denke, Sie könnten das ganz einfach hinzufügen.
Celada
@ Celada Ich habe die Änderungszeit für Dateien hinzugefügt (da ich beim Kopieren und Einfügen aus meinem Originalcode nicht weiß, ob der ZIP-Standard tatsächlich Berechtigungen hat). AFAIK (modern) tar ist in dieser Hinsicht vollständiger, da ZIP mehr auf Windows ausgerichtet ist .
Anthon
Genau das, wonach ich gesucht habe. Ich habe erwartet, dass ein solches Dienstprogramm in Standard-Unix-Paketen verfügbar sein wird. Was ist die Lizenz dafür? Ich möchte vorschlagen, dass es in einigen Paketen (z. B. Debians Devutils) enthalten ist, möglicherweise nach einigen Verallgemeinerungen.
Großbritannien
Noch ein Kommentar: Dem Verweis auf timefehlt ein import.
Großbritannien
@rbrito Ich werde das auf PyPI posten, jede Distribution kann es von dort abholen. Genau wie manche mit meinem ruamel.yaml-Paket machen. Vielen Dank für den timeKommentar, ich aktualisiere die Antwort
Anthon
5

Der tarBefehl behandelt Dateisysteme. Die Eingabe ist eine Liste von Dateien, die dann aus einem Dateisystem gelesen werden (einschließlich vieler Metadaten). Sie müssten die zip-Datei als Dateisystem präsentieren, damit der tarBefehl sie lesen kann.

Ein virtuelles Dateisystem - Mit AVFS kann jedes Programm über eine standardmäßige Dateisystemschnittstelle über FUSE in archivierte oder komprimierte Dateien schauen .

Es gibt einige detaillierte Informationen in der Readme-Datei von avfs-fuse und einige Distributionen haben Pakete dafür.

Wenn Sie AVFS installiert haben, können Sie

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

AVFS fügt alle Informationen für das Dateisystem ein, die in der ZIP-Datei fehlen, wie z. B. der Dateibesitz, den tar abholt.

Matt
quelle
0

Hier ist ein kleiner Ausschnitt, der ein ZIP-Archiv in ein passendes TAR.GZ-Archiv OnTheFly konvertiert.

Konvertieren Sie ZIP-Archiv in TAR-Archiv im laufenden Betrieb

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

Quelle

Evgeni Braverman
quelle