unzip.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. # The MIT License
  2. # Copyright (c) 2003 Doug Tolton
  3. #
  4. # Permission is hereby granted, free of charge, to any person obtaining a copy
  5. # of this software and associated documentation files (the "Software"), to deal
  6. # in the Software without restriction, including without limitation the rights
  7. # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. # copies of the Software, and to permit persons to whom the Software is
  9. # furnished to do so, subject to the following conditions:
  10. #
  11. # The above copyright notice and this permission notice shall be included in
  12. # all copies or substantial portions of the Software.
  13. #
  14. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. # THE SOFTWARE.
  21. #
  22. #
  23. """ unzip.py
  24. Version: 1.2
  25. Extract a zip file to the directory provided
  26. It first creates the directory structure to house the files
  27. then it extracts the files to it.
  28. Sample usage:
  29. Windows command line
  30. unzip.py -p 10 -z c:\testfile.zip -o c:\testoutput
  31. Linux command line
  32. unzip.py -p 10 -z /tmp/testfile.zip -o /tmp/testoutput
  33. Python class:
  34. import unzip
  35. un = unzip.unzip()
  36. un.extract(r'c:\testfile.zip', r'c:\testoutput') # Windows
  37. un.extract(r'/tmp/testfile.zip', '/tmp/testoutput') # Linux
  38. By Doug Tolton
  39. Taken from http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/252508
  40. 2009 - 2010: Updated by Daniel Jacobs to be OS-neutral and more stable.
  41. 2011: Ported to Python 3 by Daniel Jacobs.
  42. """
  43. import sys
  44. import zipfile
  45. import os
  46. import os.path
  47. import optparse
  48. import errno
  49. class unzip:
  50. def __init__(self, verbose = False, percent = 10):
  51. self.verbose = verbose
  52. self.percent = percent
  53. def extract(self, file, dir):
  54. """ Extract all the files in the zip file, "file" to the directory "dir" with full path names."""
  55. if not dir.endswith(':') and not os.path.exists(dir):
  56. self._makedir(dir)
  57. zf = zipfile.ZipFile(file)
  58. # create directory structure to house files
  59. self._createstructure(file, dir)
  60. num_files = len(zf.namelist())
  61. percent = self.percent
  62. divisions = 100 // percent
  63. perc = int(num_files // divisions)
  64. # extract files to directory structure
  65. for i, name in enumerate(zf.namelist()):
  66. if self.verbose == True:
  67. print("Extracting {0}".format(name))
  68. elif perc > 0 and (i % perc) == 0 and i > 0:
  69. complete = int (i // perc) * percent
  70. print("{0}% complete".format(complete))
  71. if not name.endswith('/'):
  72. # Normalise the path so that it is correct for the current OS
  73. localdirname = os.path.normpath(os.path.join(dir, os.path.dirname(name)))
  74. # Ensure that the directory hierarchy that contains the files exists so that
  75. # writing to the file is valid. Note: some zip tools omit directory information
  76. # and this will cause problems when trying to write file to non-existent directories.
  77. self._makedir(localdirname)
  78. # Write the file
  79. outfile = open(os.path.join(localdirname, os.path.basename(name)), 'wb')
  80. outfile.write(zf.read(name))
  81. outfile.flush()
  82. outfile.close()
  83. zf.close()
  84. def _createstructure(self, file, dir):
  85. self._makedirs(self._listdirs(file), dir)
  86. def _makedirs(self, directories, basedir):
  87. """ Create any directories that don't currently exist """
  88. for dir in directories:
  89. curdir = os.path.join(basedir, dir)
  90. # Normalise path for current OS.
  91. curdir = os.path.normpath(curdir)
  92. self._makedir(curdir)
  93. def _makedir(self, directory):
  94. """ Create a directory "safely", catching the "file exists" exception if the
  95. directory has been created by another process. Creates all parent directories
  96. recursively as required. """
  97. if not os.path.exists(directory):
  98. # In multi-threaded uses, it is possible that this directory
  99. # has been made in the meantime. Catch this exception.
  100. try:
  101. os.makedirs(directory)
  102. except OSError(aOSError):
  103. # If the OSError is that the file exists then we are OK - this
  104. # might occur in a multi-threaded or multi-process environment;
  105. # otherwise re-raise the exception since it's something else bad.
  106. if aOSError.errno != errno.EEXIST:
  107. raise aOSError
  108. def _listdirs(self, file):
  109. """ Grabs all the directories in the zip structure
  110. This is necessary to create the structure before trying
  111. to extract the file to it. """
  112. zf = zipfile.ZipFile(file)
  113. dirs = []
  114. for name in zf.namelist():
  115. if name.endswith('/'):
  116. if self.verbose == True:
  117. print("Directory \"{0}\" will be made.".format(name))
  118. dirs.append(name)
  119. zf.close()
  120. return dirs
  121. def main():
  122. parser = optparse.OptionParser()
  123. parser.add_option("-z", "--zipfile", dest = "zipfile", help = "the zip file to extract")
  124. parser.add_option("-o", "--outdir", dest = "zipdest", help = "target location")
  125. parser.add_option("-p", "--percent", dest = "percent", type = "int", help = "sets the percentage notification")
  126. parser.add_option("-v", "--verbose", dest = "verbose", help = "sets the extraction to verbose (overrides -p)", action = "store_true", default = False)
  127. (options, args) = parser.parse_args()
  128. unzipper = unzip()
  129. zipsource = ""
  130. zipdest = ""
  131. if options.verbose:
  132. unzipper.verbose = True
  133. if options.percent:
  134. unzipper.percent = options.percent
  135. if options.zipfile:
  136. zipsource = options.zipfile
  137. else:
  138. sys.stderr.write("Error - no zip file given.\n")
  139. sys.exit(2)
  140. if options.zipdest:
  141. zipdest = options.zipdest
  142. else:
  143. sys.stderr.write("Error - no destination directory given.\n")
  144. sys.exit(2)
  145. unzipper.extract(zipsource, zipdest)
  146. if __name__ == '__main__':
  147. main()