有没有一种方法可以将zip转换为tar而无需将其解压缩到文件系统中?


17

有没有一种方法可以将zip存档转换为tar存档而无需先提取到临时目录?(并且无需编写我自己的tar或实现unzip


您是否认为将zip归档文件安装为将其解压缩到文件系统中?如果是,那么您无需使用libarchive即可提取任何内容,而无需进行任何编码即可做到这一点。
Celada's

我认为操作人员正在寻找类似superuser.com/questions/325504/…的东西,这是您希望实现的目标吗?
vfbsilva 2014年

Answers:


12

现在,可以从PyPI将其作为可安装命令使用,请参阅本文结尾。


我不知道这样做的任何“标准”实用程序,但是当我需要此功能时,我编写了以下Python脚本,从ZIP压缩到Bzip2压缩的tar存档,而没有先提取任何内容到磁盘:

#! /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文件小得多,因为zip文件不对多个文件使用压缩模式,但是如果Bzip2文件中的某些内容有误,则恢复以后的文件的可能性也较小。

如果您不希望压缩输出,请从代码中删除:bz2.bz2


如果您已pip安装在python3环境中,则可以执行以下操作:

pip3 install ruamel.zip2tar

获得zip2tar执行上述操作的命令行实用程序(免责声明:我是该软件包的作者)。


1
好一个。脚本似乎没有尝试复制元数据(例如文件修改时间和整个存档格式更改的权限)的任何尝试,但是我认为您可以很轻松地添加它。
Celada 2014年

@Celada我添加了文件修改时间(错过了从原始代码进行复制和粘贴时的时间),我不确定ZIP标准是否实际上具有权限,在这方面AFAIK(现代)tar是否更完整,而ZIP更面向Windows 。
Anthon 2014年

正是我想要的。我希望可以从标准的unix软件包中获得这样一个实用程序。这是什么许可证?我想建议将它包含在某些软件包中(例如,Debian的devutils),也许经过一些概括。
rbrito

另一条评论:对的引用time缺少import
rbrito

@rbrito我会将其发布在PyPI上,任何发行版都可以从那里获取。就像我的ruamel.yaml包一样。感谢您的time评论,我更新了答案
Anthon 2015年

5

tar命令处理文件系统。它的输入是文件列表,然后从文件系统中读取文件列表(包括很多元数据)。您需要将zip文件显示为文件系统,tar命令才能读取它。

虚拟文件系统-AVFS将允许任何程序通过FUSE通过标准文件系统界面查看已存档或压缩的文件。

avfs-fuse自述文件中有一些详细信息,某些发行版 包含用于此文件的软件包

一个已经安装了AVFS,然后您就可以

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

AVFS将填写zip会丢失的zip文件中缺少的文件系统的任何信息,例如文件所有权。


0

这是一个将SIP存档转换为匹配的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)

资源

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.