4

Presume I have an archive, foo.zip. It contains the parts of a shapefile: foo.shp, foo.dbf, foo.shx, foo.prj, and foo.cpg. I want to work with this shapefile in python, using pyshp, AKA the shapefile library.

Right now, I can extract the archive to disk, then read in the shapefile:

r = shapefile.Reader('foo')

I have quite a few such archives, though, and it would be nice to be able to read in these files without having to first extract each archive. According to pyshp's documentation, you can read in a file-like object with syntax like this:

myshp = open('foo.shp', 'rb')
mydbf = open('foo.dbf', 'rb')
r = shapefile.Reader(shp=myshp, dbf=mydbf)

And I quote: "This feature is very powerful and allows you to load shapefiles from a url, from a zip file, serialized object, or in some cases a database."

Thus I have tried creating a file-like object from my archive. First, creating the archive:

archive = zipfile.ZipFile('foo.zip')

Works fine. But if I then try

r = shapefile.Reader(archive.open('foo.shp')

I get the error, "shapefile.ShapefileException: Shapefile Reader requires a shapefile or file-like object."

That's legit; I should be passing it a file-like object. So I tried modifying the documentation's canonical example:

myshp = archive.open('foo.shp', 'r')
mydbf = archive.open('foo.dbf', 'r')
r = shapefile.Reader(shp=myshp, dbf=mydbf)

But this produces the error, "io.UnsupportedOperation: seek".

For what it is worth, I cannot use 'rb' as an option with archive.open(). If I do, I am told, "RuntimeError: open() requires mode 'r', 'U', or 'rU'". Also, using "archive.read()" instead of "archive.open()" just produces the "...requires a shapefile or file-like object" error.

I am stumped. As far as I can tell, I have created archive correctly, I have correctly used archive.open() to grab files as file-like objects, and I have used the correct syntax to have pyshp read from a file-like object. And yet, these errors. Does anyone have any idea what I'm doing wrong here? Has anyone had success passing file-like objects from zip archives to pyshp?

2

I have been using StringIO for reading zipped shapefiles with pyshp and it worked fine.

#shapefile.__version__ '1.2.3'


from __future__ import print_function
import zipfile
import StringIO
import shapefile

zipshape = zipfile.ZipFile(open(r'C:\GIS\Temp\RoadsShapefileFolder.zip', 'rb'))
print(zipshape.namelist())
dbfname, _, shpname, _, shxname = zipshape.namelist()
r = shapefile.Reader(shp=StringIO.StringIO(zipshape.read(shpname)),
                     shx=StringIO.StringIO(zipshape.read(shxname)),
                     dbf=StringIO.StringIO(zipshape.read(dbfname)))

print(r.bbox)
print(r.numRecords)

Output:

['Roads.dbf', 'Roads.prj', 'Roads.shp', 'Roads.shp.xml', 'Roads.shx']
[279629.7664999999, 6137207.9419, 916929.7043000003, 7595571.024099998]
365

Make sure you access the right files within the zip as they are sorted alphabetically.

  • Thank you--that seemed to do the trick. On this other thread, someone noted that "read returns a string with the file's contents; open returns a file-like object." It seems telling that reading and then passing through StringIO works, while the straight open does not seem to. Odd--but I'll take this solution! – JP Ferguson Jul 27 '17 at 17:01
  • In python 3 you should use BytesIO from the io package. – webelo Mar 7 '18 at 19:16

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.