Reputation: 11295
Initially I was thinking of using os.path.isdir
but I don't think this works for zip files. Is there a way to peek into the zip file and verify that this directory exists? I would like to prevent using unzip -l "$@"
as much as possible, but if that's the only solution then I guess I have no choice.
Upvotes: 18
Views: 26829
Reputation: 48028
Not listed here, but this can be be done as a dictionary lookup.
import os, zipfile
def zip_contains_dir(zip_handle, path):
# Ensure trailing slash.
path = path.rstrip("/") + "/"
return path in zip_handle.NameToInfo
with zipfile.ZipFile("myfile.zip") as zip_handle:
print(zip_contains_dir(zip_handle, "some/dir"))
Upvotes: 0
Reputation: 211
this is how the is_dir()
implemented in python source code:
def is_dir(self):
"""Return True if this archive member is a directory."""
return self.filename[-1] == '/'
It simply checks if the filename ends with a slash /
, Can't tell if this will work correctly in some certain circumstances(so IMO it is badly implemented).
as print(zipinfo)
will show filemode
but no corrsponding property or field is provided, I dive into zipfile module source code and found how it is implemented.
(see def __repr__(self):
https://github.com/python/cpython/blob/3.6/Lib/zipfile.py)
if you want something simple and easy, this will work in most cases but it may fail because in some cases this field will not be printed.
def is_dir(zipinfo):
return "filemode='d" in zipinfo.__repr__()
my solution is to check file mode manually and decide if the referenced file is actually a directory inspired by https://github.com/python/cpython/blob/3.6/Lib/zipfile.py line 391.
def is_dir(fileinfo):
hi = fileinfo.external_attr >> 16
return (hi & 0x4000) > 0
Upvotes: 2
Reputation: 64563
Just check the filename with "/" at the end of it.
import zipfile
def isdir(z, name):
return any(x.startswith("%s/" % name.rstrip("/")) for x in z.namelist())
f = zipfile.ZipFile("sample.zip", "r")
print isdir(f, "a")
print isdir(f, "a/b")
print isdir(f, "a/X")
You use this line
any(x.startswith("%s/" % name.rstrip("/")) for x in z.namelist())
because it is possible that archive contains no directory explicitly; just a path with a directory name.
Execution result:
$ mkdir -p a/b/c/d
$ touch a/X
$ zip -r sample.zip a
adding: a/ (stored 0%)
adding: a/X (stored 0%)
adding: a/b/ (stored 0%)
adding: a/b/c/ (stored 0%)
adding: a/b/c/d/ (stored 0%)
$ python z.py
True
True
False
Upvotes: 15
Reputation: 9711
You can accomplish this using the built-in library ZipFile.
import zipfile
z = zipfile.ZipFile("file.zip")
if "DirName/" in [member.filename for member in z.infolist()]:
print("Directory exists in archive")
Tested and functional with Python32.
Upvotes: 0
Reputation: 7674
You can check for the directories with ZipFile.namelist().
import os, zipfile
dir = "some/directory/"
z = zipfile.ZipFile("myfile.zip")
if dir in z.namelist():
print "Found %s!" % dir
Upvotes: 8