Is there a way to convert a zip archive to a tar archive without extracting to a temporary directory first? (and without writing my own implementation of tar or unzip)


This is now available as installable command from PyPI, see the end of this post.

I don't know of any "standard" utility that does so, but when I needed this functionality I wrote the following Python script to go from ZIP to Bzip2 compressed tar archives without extracting anything to disk first:

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

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)

Just save it to zip2tar and make it executable or save it to zip2tar.py and run python zip2tar.py. Provide the ZIP filename as an argument to the script, the output filename for xyz.zip will be xyz.tar.bz2.

The Bzip2 compressed output is normally much smaller than the zip file because the latter doesn't use compression patterns over multiple files, but there is also less chance of recovering later file if something in the Bzip2 file is wrong.

If you don't want the output compressed, remove :bz2 and .bz2 from the code.

If you have pip installed in a python3 environment, you can do:

pip3 install ruamel.zip2tar

to get a zip2tar commandline utility doing the above (disclaimer: I am the author of that package).

  • 1
    Nice one. It looks like the script does not make any attempt to copy metadata such as file modification time and permissions across the archive format change, but I think you could add that quite easily. – Celada Jul 24 '14 at 6:11
  • @Celada I added the file modification time (missed that while copy and pasting from my orginal code), I am not sure if the ZIP standard actually has permissions, AFAIK (modern) tar is more complete in that respect with ZIP more being Windows oriented. – Anthon Jul 24 '14 at 6:24
  • Exactly what I was looking for. I expected one utility like this to be available from standard unix packages. What is the license of this? I would like to propose it to be included in some packages (e.g., Debian's devutils), perhaps after some generalizations. – rbrito Jul 1 '15 at 13:04
  • Another comment: the reference to time lacks an import. – rbrito Jul 1 '15 at 13:06
  • @rbrito I will post this on PyPI, any distro can pick it up from there. Just like some do with my ruamel.yaml package. Thanks for the time comment, I update the answer – Anthon Jul 1 '15 at 19:37

The tar command deals with file systems. It's input is a list of files that it then reads from a file system (including a lot of metadata). You would need to present the zip file as a file system for the tar command to read it.

A Virtual File System - AVFS will allow any program to look inside archived or compressed files via a standard file system interface via FUSE.

There's some detailed information in the avfs-fuse readme and some distributions have packages for it.

One you have AVFS installed, then you can

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

AVFS will fill in any information for the file system that is missing from the zip, like file ownership, that tar will pick up.


Here’s a small snippet that converts a ZIP archive to a matching TAR.GZ archive OnTheFly.

Convert ZIP archive to TAR archive on the fly

# 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("/"):

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


# convert all ZIP files in the current directory
for file in glob.glob("*.zip"):


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.