Есть ли способ конвертировать zip в tar, не распаковывая его в файловую систему?

17

Есть ли способ конвертировать zipархив в tarархив без предварительного извлечения во временный каталог? (и без написания моей собственной реализации tarили unzip)

user253751
источник
Считаете ли вы монтирование zip-архива как извлечение его в файловую систему? Если да, то вы можете сделать это без извлечения что-либо с помощью libarchive, но это включает в себя кодирование.
Селада
Я думаю, что опера ищет что-то вроде этого superuser.com/questions/325504/… это то, чего вы надеетесь достичь?
vfbsilva

Ответы:

12

Теперь это доступно как устанавливаемая команда из PyPI, см. Конец этого поста.


Я не знаю ни одной «стандартной» утилиты, которая бы это делала, но когда мне понадобилась эта функциональность, я написал следующий скрипт на Python для перехода от ZIP к сжатым архивам tar Bzip2 без предварительного извлечения чего-либо на диск:

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

Просто сохраните его zip2tarи сделайте его исполняемым или сохраните его zip2tar.pyи запустите python zip2tar.py. Укажите имя файла ZIP в качестве аргумента сценария. Выходное имя файла xyz.zipбудетxyz.tar.bz2 .

Сжатый вывод Bzip2 обычно намного меньше, чем файл zip, поскольку последний не использует шаблоны сжатия для нескольких файлов, но также меньше шансов восстановить более поздний файл, если что-то в файле Bzip2 неверно.

Если вы не хотите сжатие вывода, удалите :bz2и .bz2из кода.


Если вы pipустановили в среде Python3, вы можете сделать:

pip3 install ruamel.zip2tar

чтобы получить zip2tarутилиту командной строки, делающую вышеуказанное (отказ от ответственности: я являюсь автором этого пакета).

Энтон
источник
1
Хороший. Похоже, что скрипт не делает никаких попыток скопировать метаданные, такие как время изменения файла и разрешения для изменения формата архива, но я думаю, что вы могли бы добавить это довольно легко.
Селада
@Celada Я добавил время модификации файла (пропустил это при копировании и вставке из моего оригинального кода), я не уверен, действительно ли у стандарта ZIP есть разрешения, AFAIK (современный) tar более полон в этом отношении, ZIP больше ориентирован на Windows ,
Энтон
Именно то, что я искал. Я ожидал, что такая утилита будет доступна из стандартных пакетов Unix. Какова лицензия этого? Я хотел бы предложить включить его в некоторые пакеты (например, в devutils Debian), возможно, после некоторых обобщений.
rbrito
Еще один комментарий: ссылка на timeне хватает import.
rbrito
@rbrito Я опубликую это на PyPI, любой дистрибутив может получить его оттуда. Как некоторые делают с моим пакетом ruamel.yaml. Спасибо за timeкомментарий, я обновляю ответ
Anthon
5

Команда tarимеет дело с файловыми системами. Входные данные представляют собой список файлов, которые затем считываются из файловой системы (включая большое количество метаданных). Вам нужно будет представить zip-файл как файловую систему для tarкоманды, чтобы прочитать его.

Виртуальная файловая система - AVFS позволяет любой программе просматривать архивные или сжатые файлы через стандартный интерфейс файловой системы через FUSE .

В файле readme для avfs-fuse есть некоторая подробная информация, и в некоторых дистрибутивах есть пакеты для этого.

Один у вас установлен AVFS, то вы можете

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

AVFS заполнит любую информацию для файловой системы, которая отсутствует в zip-файле, например, о принадлежности файла, которую подберет tar.

Matt
источник
0

Вот небольшой фрагмент, который преобразует ZIP-архив в соответствующий архив TAR.GZ OnTheFly.

Конвертировать ZIP архив в TAR архив на лету

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

Источник

Евгений Браверман
источник