17

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.

Stupid.Fat.Cat
  • 10,755
  • 23
  • 83
  • 144

4 Answers4

14

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
Igor Chubin
  • 61,765
  • 13
  • 122
  • 144
8

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
enderskill
  • 7,354
  • 3
  • 24
  • 23
2

for python(>=3.6):

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).

for python(<3.6):

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)

possibly a bad idea but it will work:

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__()

Finally:

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
imkzh
  • 211
  • 2
  • 9
0

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.

Lanaru
  • 9,421
  • 7
  • 38
  • 64
  • You are trying to use a docx file instead of a zip? Rename the extension to .zip and try it again, it should work. – Lanaru Jul 23 '12 at 17:56
  • It works fine unzipping, and I can get it to print all the files. But the directory "word" is not in namelist(), rather individual files, such as word/webSettings.xml so it's not getting a match. – Stupid.Fat.Cat Jul 23 '12 at 17:57