Skip to content Skip to sidebar Skip to footer

Python Zip A Sub Folder And Not The Entire Folder Path

I have a program to zip all the contents in a folder. I did not write this code but I found it somewhere online and I am using it. I intend to zip a folder for example say, C:/fold

Solution 1:

You'll have to give an arcname argument to ZipFile.write() that uses a relative path. Do this by giving the root path to remove to makeArchive():

def makeArchive(fileList, archive, root):
    """
    'fileList' is a list of file names - full path each name
    'archive' is the file name for the archive with a full path
    """
    a = zipfile.ZipFile(archive, 'w', zipfile.ZIP_DEFLATED)

    for f in fileList:
        print "archiving file %s" % (f)
        a.write(f, os.path.relpath(f, root))
    a.close()

and call this with:

makeArchive(dirEntries(folder, True), zipname, folder)

I've removed the blanket try:, except:; there is no use for that here and only serves to hide problems you want to know about.

The os.path.relpath() function returns a path relative to root, effectively removing that root path from the archive entry.

On python 2.5, the relpath function is not available; for this specific usecase the following replacement would work:

def relpath(filename, root):
    return filename[len(root):].lstrip(os.path.sep).lstrip(os.path.altsep)

and use:

a.write(f, relpath(f, root))

Note that the above relpath() function only works for your specific case where filepath is guaranteed to start with root; on Windows the general case for relpath() is a lot more complex. You really want to upgrade to Python 2.6 or newer if at all possible.


Solution 2:

ZipFile.write has an optional argument arcname. Use this to remove parts of the path.

You could change your method to be:

def makeArchive(fileList, archive, path_prefix=None):
    """
    'fileList' is a list of file names - full path each name
    'archive' is the file name for the archive with a full path
    """
    try:
        a = zipfile.ZipFile(archive, 'w', zipfile.ZIP_DEFLATED)

        for f in fileList:
            print "archiving file %s" % (f)
            if path_prefix is None:
                a.write(f)
            else:
                a.write(f, f[len(path_prefix):] if f.startswith(path_prefix) else f)
        a.close()
        return True
    except: return False 

Martijn's approach using os.path is much more elegant, though.


Post a Comment for "Python Zip A Sub Folder And Not The Entire Folder Path"