Script for Making Individual Zip file for Each Shapefile?

6590
16
05-29-2013 05:47 AM
JacobCoble
New Contributor
I posted this in the Geoprocessing forum and then I thought I should post it here - sorry if this is redundant.

I need to take all of the shapefiles in a directory and compress them into individual zip files. I need to take, for example, the roads shapefile and get all of the files named roads.* into roads.zip, the schools shapefile, schools.* into schools.zip, and so on, for hundreds of shapefiles.
Tags (2)
0 Kudos
16 Replies
by Anonymous User
Not applicable
This worked for me:

import arcpy, os
from os import path as p
import zipfile
arcpy.overwriteOutput = True


def ZipShapes(path, out_path):
    arcpy.env.workspace = path
    shapes = arcpy.ListFeatureClasses()

    # iterate through list of shapefiles
    for shape in shapes:
        name = p.splitext(shape)[0]
        print name
        zip_path = p.join(out_path, name + '.zip')
        zip = zipfile.ZipFile(zip_path, 'w')
        zip.write(p.join(path,shape), shape)
        for f in arcpy.ListFiles('%s*' %name):
            if not f.endswith('.shp'):
                zip.write(p.join(path,f), f)
        print 'All files written to %s' %zip_path
        zip.close()

if __name__ == '__main__':

    path = r'C:\Shape_test\Census_CedarCo'
    outpath = r'C:\Shape_outputs'

    ZipShapes(path, outpath)
    


Just fill in your own variables for the ones highlighted in red. The "path" variable is the workspace containing all shapefiles to be zipped. The "outpath" variable is the output location for all your zipped folders for each shapefile.

Edit: I added an additional part to get rid of the subfolders created in the zip (the arcname argument for the zip.write).
JacobCoble
New Contributor
Thanks, Caleb, that worked!

One thing I noticed, though is that it did not actually compress the files (they were archived in zip files but not compressed).
I changed a line
from this:
        zip = zipfile.ZipFile(zip_path, 'w')
     
to this:
        zip = zipfile.ZipFile(zip_path, 'w',
        compression=zipfile.ZIP_DEFLATED)

and now the zipped files are compressed.

Thanks again for your help.

Jacob
0 Kudos
by Anonymous User
Not applicable
One thing I noticed, though is that it did not actually compress the files (they were archived in zip files but not compressed).


Ahh, good eye!  I did not realize that they were not getting compressed.  I suppose I just assumed that automatically happened when writing the zip files.  That's good to know. Glad it did the trick tho!
0 Kudos
JacobCoble
New Contributor
So the script above works perfectly, with ArcGIS 10. But I just realized that it has to run in ArcGIS 9.3.1 instead! I tried importing arcgisscripting instead of arcpy and changed code from, for example,
shapes = arcpy.ListFeatureClasses()
to
shapes = gp.ListFeatureClasses()
but I get errors.

It seems like it does not know what the workspace is, so at least the first error is in here where the workspace is defined:
def ZipShapes(path, out_path):
    gp.env.workspace = path
    shapes = gp.ListFeatureClasses()

I appreciate any suggestions.
0 Kudos
JasonScheirer
Occasional Contributor III
Set gp.workspace, not gp.env.workspace
0 Kudos
JacobCoble
New Contributor
I tried gp.workspace = path and I get a "object is not iterable" error. Below is my attempt at 9.3.1 code and below that is the error. I am sure someone will see something obvious that I am missing. Edit: Here the indents are missing - the indents don't show up when I pasted the code here but you get the idea.


#Begin code
import sys, string, arcgisscripting, os
from os import path as p
import zipfile

# Create the Geoprocessor object
gp = arcgisscripting.create()

# arcpy.overwriteOutput = True
gp.overwriteoutput=1

def ZipShapes(path, out_path):
    gp.workspace = path
    shapes = gp.ListFeatureClasses()

    # iterate through list of shapefiles
    for shape in shapes:
        name = p.splitext(shape)[0]
        print name
        zip_path = p.join(out_path, name + '.zip')
        zip = zipfile.ZipFile(zip_path, 'w',
        compression=zipfile.ZIP_DEFLATED)
        zip.write(p.join(path,shape), shape)
        for f in gp.ListFiles('%s*' %name):
            if not f.endswith('.shp'):
                zip.write(p.join(path,f), f)
        print 'All files written to %s' %zip_path
        zip.close()

if __name__ == '__main__':

    path = r'T:\\cotiss\\CobleJ\\shape2zip\\address'
    outpath = r'T:\\cotiss\\CobleJ\\shape2zip\\Shape_outputs'

    ZipShapes(path, outpath)
#End of code


HERE is the ERROR:
Traceback (most recent call last):
  File "T:\cotiss\CobleJ\shape2zip\Shape2Zip_931.py", line 34, in <module>
    ZipShapes(path, outpath)
  File "T:\cotiss\CobleJ\shape2zip\Shape2Zip_931.py", line 16, in ZipShapes
    for shape in shapes:
TypeError: 'geoprocessing list object' object is not iterable
0 Kudos
JasonScheirer
Occasional Contributor III
The list functions don't return lists if your geoprocessor is set above 9.3. To make it run in 9.3 mode, do this:

gp = arcgisscripting.create(9.3)


This will ensure the same behavior of this script even in 10.0/10.1. Then, use this idiom:

for shape in iter(shapes.next, None):


Since it returns a geoprocessing list object and not a Python list in 9.3.
0 Kudos
JacobCoble
New Contributor
I don't think ListFiles is recognized in 9.3.1. I seem to have a problem with that.
0 Kudos
by Anonymous User
Not applicable
You can use the os.walk() and fnmatch to get the file names:

import fnmatch, os

for shape in shapes:
    name = p.splitext(shape)[0]:
    zip_path = p.join(out_path, name + '.zip')
    zip = zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED)
    zip.write(p.join(path,shape), shape)
    for path, dirs, files in os.walk(path):
        for f in files:
            if fnmatch.fnmatch(f, '%s*' %shape):
                zip.write(p.join(path,f), f)
    print 'All files written to %s' %zip_path
    zip.close()



By using fnmatch you can provide a pattern for it to search for when looking through files so if your shapefile name is roads.shp, it can search all files that are like 'roads*'.
0 Kudos