Script to make Windows XP-readable ZIP file

Carl Banks invalidemail at aerojockey.com
Thu May 18 23:16:03 EDT 2006


pac wrote:
> Suppose you have a set of files in a directory c:\a\b and some
> additional
> files in c:\a\b\subdir.  Using a Python script, you would
> like to make a Windows-readable archive (.zip) that preserves this
> directory structure, and where the root directory of the archive is
> c:\a\b.  In other words, all the files from c:\a\b appear in the
> archive
> without a path prefix, and all the files in c:\a\b\subdir have a path
> prefix of \subdir.
>
> This looks like it should be easy with module zipfile and the handy
> function os.walk.  Create a zip file, call os.walk, and add the files
> to
> the archive like so:
>
> import os
> import zipfile
>
> z =
> zipfile.ZipFile(r"c:\a\b\myzip.zip",mode="w",compression=zipfile.ZIP_DEFLATED)
>
> for dirpath,dirs,files in os.walk(r"c:\a\b"):
>     for a_file in files:
>         a_path = os.path.join(dirpath,a_file)
>         z.write(a_path)  # Change, see below
> z.close()

(Aside: be careful not to use tabs when posting.  I suspect the f-bot
will be here to tell you that the above code doesn't work.)

> Some experimentation suggests that Windows does not like any filename
> in the
> archive that begins with either a drive designator like c:, or has a
> path containing
> a leading slash like "\a\b\afile.txt".  Relative paths like
> "subdir\afile.txt" are
> okay, and cause the desired behavior when the archive is extracted,
> e.g., a new directory subdir is created and afile.txt is placed in it.
>
> Since the method ZipFile.write needs a valid pathname for each file,
> the correct
> solution to the original problem entails messing around with the OS's
> current
> working directory.

ZipFile.write takes an optional second argument for the archive
filename.  You could have done something like this (untested):

for dirpath,dirs,files in os.walk(r"c:\a\b"):
    for a_file in files:
        a_path = os.path.join(dirpath,a_file)
        z_path = a_path[7:]  # or whatever
        z.write(a_path,z_path)
z.close()

And maybe use a little helper function instead of the string slice to
make it more robust (it violates DRY, and I'm not happy to assume the
dirpath returned by os.walk has exactly the same prefix as the
argument).

>  Position the CWD in the desired base directory of
> the archive,
> add the files to the archive using their relative pathnames, and put
> the CWD back
> where it was when you started:

This may be the best way anyways, unless you have some reason to not
change the current directory.


Carl Banks




More information about the Python-list mailing list