Wednesday, September 12, 2012

Zip Files & Folders with Python ZipFile

Here is my code to create a zip file using Python's ZipFile module.  The code works for individual files, folders, and wildcards, etc.

Usage:

1. Create a blank  / empty Zip file:

Zip(r'c:\temp\foo.zip')


2. Create a zip file for files and folders

Zip(r'c:\temp\foo.zip', [r'*.txt', r'Folder', r'Folder2\*.txt'])

3. Create a zip file with nice sub directory names

    Assume following directory structure.
        c:\temp
        c:\temp\Apple\Pie.txt
        c:\temp\Orange\Slice.txt
        c:\temp\Banana\Pudding.txt
    Set the current directory to c:\temp & execute following command will create a Zip file with following path names:
    # set current working directory to c:\temp
    Zip(r'c:\temp\foo.zip', [r'c:\temp\Apple', r'c:\temp\Orange', r'c:\temp\Banana'])

    Apple\Pie.txt
    Orange\Slice.txt
    Banana\Pudding.txt
Code:

import collections
import glob
import os
import re
import shutil
import sys
import threading
import time
import zipfile


# Helper function to retrieve files from a list of paths.  Paths can contain wildcards

def FileListFromPathList(PathList=[]):
    if not isinstance(PathList, list):
        PathList = [PathList]

    for path in PathList:
        if not path.strip():
            continue

        path = os.path.abspath(path)
        for found in glob.glob(path):
            if os.path.isfile(found):
                yield found
            else:
                for base, dirs, files in os.walk(found):
                    for file in files:
                        yield os.path.join(base, file)

# Function to do the zipping
def Zip(ZipFilePath, PathList=[], Mode='w', ZipFolderPrefix='', FromCurrentDirectory=True):
    ZipFilePath = Expand(ZipFilePath)

    cwd = os.getcwd()
    rootlen = len(cwd) + 1

    if ZipFolderPrefix:
        ZipFolderPrefix = ZipFolderPrefix + r'\\'

    def MakeZipFolderName(FilePath):
        if FromCurrentDirectory and cwd in FilePath:
            return ZipFolderPrefix + FilePath[rootlen:]
        else:
            return ZipFolderPrefix + os.path.basename(FilePath)

    zipFile = zipfile.ZipFile(ZipFilePath, Mode)

    print r'Zipping to %s' % (ZipFilePath)
    for path in FileListFromPathList(PathList):
        zipPath = MakeZipFolderName(path)
        print r'   Zipping %s' % (zipPath)
        zipFile.write(path, zipPath)

    zipFile.close()