|
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 |
|
24 """ unzip.py |
|
25 Version: 1.1 |
|
26 |
|
27 Extract a zip file to the directory provided |
|
28 It first creates the directory structure to house the files |
|
29 then it extracts the files to it. |
|
30 |
|
31 Sample usage: |
|
32 Windows command line |
|
33 unzip.py -p 10 -z c:\testfile.zip -o c:\testoutput |
|
34 |
|
35 Linux command line |
|
36 unzip.py -p 10 -z /tmp/testfile.zip -o /tmp/testoutput |
|
37 |
|
38 Python class: |
|
39 import unzip |
|
40 un = unzip.unzip() |
|
41 un.extract(r'c:\testfile.zip', r'c:\testoutput') # Windows |
|
42 un.extract(r'/tmp/testfile.zip', '/tmp/testoutput') # Linux |
|
43 |
|
44 By Doug Tolton |
|
45 |
|
46 Taken from http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/252508 |
|
47 |
|
48 Updated by Daniel Jacobs to be OS-neutral and more stable. |
|
49 """ |
|
50 |
|
51 import sys |
|
52 import zipfile |
|
53 import os |
|
54 import os.path |
|
55 import getopt |
|
56 import errno |
|
57 |
|
58 class unzip: |
|
59 def __init__(self, verbose = False, percent = 10): |
|
60 self.verbose = verbose |
|
61 self.percent = percent |
|
62 |
|
63 def extract(self, file, dir): |
|
64 """ Extract all the files in the zip file, "file" to the directory "dir" with full path names.""" |
|
65 if not dir.endswith(':') and not os.path.exists(dir): |
|
66 self._makedir(dir) |
|
67 |
|
68 zf = zipfile.ZipFile(file) |
|
69 |
|
70 # create directory structure to house files |
|
71 self._createstructure(file, dir) |
|
72 |
|
73 num_files = len(zf.namelist()) |
|
74 percent = self.percent |
|
75 divisions = 100 / percent |
|
76 perc = int(num_files / divisions) |
|
77 |
|
78 # extract files to directory structure |
|
79 for i, name in enumerate(zf.namelist()): |
|
80 |
|
81 if self.verbose == True: |
|
82 print "Extracting %s" % name |
|
83 elif perc > 0 and (i % perc) == 0 and i > 0: |
|
84 complete = int (i / perc) * percent |
|
85 print "%s%% complete" % complete |
|
86 |
|
87 if not name.endswith('/'): |
|
88 # Normalise the path so that it is correct for the current OS |
|
89 localdirname = os.path.normpath(os.path.join(dir, os.path.dirname(name))) |
|
90 |
|
91 # Ensure that the directory hierarchy that contains the files exists so that |
|
92 # writing to the file is valid. Note: some zip tools omit directory information |
|
93 # and this will cause problems when trying to write file to non-existent directories. |
|
94 self._makedir(localdirname) |
|
95 |
|
96 # Write the file |
|
97 outfile = open(os.path.join(localdirname, os.path.basename(name)), 'wb') |
|
98 outfile.write(zf.read(name)) |
|
99 outfile.flush() |
|
100 outfile.close() |
|
101 |
|
102 zf.close() |
|
103 |
|
104 |
|
105 def _createstructure(self, file, dir): |
|
106 self._makedirs(self._listdirs(file), dir) |
|
107 |
|
108 |
|
109 def _makedirs(self, directories, basedir): |
|
110 """ Create any directories that don't currently exist """ |
|
111 for dir in directories: |
|
112 curdir = os.path.join(basedir, dir) |
|
113 # Normalise path for current OS. |
|
114 curdir = os.path.normpath(curdir) |
|
115 self._makedir(curdir) |
|
116 |
|
117 |
|
118 def _makedir(self, directory): |
|
119 """ Create a directory "safely", catching the "file exists" exception if the |
|
120 directory has been created by another process. Creates all parent directories |
|
121 recursively as requied. """ |
|
122 if not os.path.exists(directory): |
|
123 # In multi-threaded uses, it is possible that this directory |
|
124 # has been made in the meantime. Catch this exception. |
|
125 try: |
|
126 os.makedirs(directory) |
|
127 except OSError, aOSError: |
|
128 # If the OSError is that the file exists then we are OK - this |
|
129 # might occur in a multi-threaded or multi-process environment; |
|
130 # otherwise re-raise the exception since it's something else bad. |
|
131 if aOSError.errno != errno.EEXIST: |
|
132 raise aOSError |
|
133 |
|
134 def _listdirs(self, file): |
|
135 """ Grabs all the directories in the zip structure |
|
136 This is necessary to create the structure before trying |
|
137 to extract the file to it. """ |
|
138 zf = zipfile.ZipFile(file) |
|
139 |
|
140 dirs = [] |
|
141 |
|
142 for name in zf.namelist(): |
|
143 if name.endswith('/'): |
|
144 if self.verbose == True: |
|
145 print "Directory \"" + name + "\" will be made." |
|
146 dirs.append(name) |
|
147 |
|
148 zf.close() |
|
149 return dirs |
|
150 |
|
151 def usage(): |
|
152 print """usage: unzip.py -z <zipfile> -o <targetdir> |
|
153 <zipfile> is the source zipfile to extract |
|
154 <targetdir> is the target destination |
|
155 |
|
156 -z zipfile to extract |
|
157 -o target location |
|
158 -p sets the percentage notification |
|
159 -v sets the extraction to verbose (overrides -p) |
|
160 |
|
161 long options also work: |
|
162 --verbose |
|
163 --percent=10 |
|
164 --zipfile=<zipfile> |
|
165 --outdir=<targetdir>""" |
|
166 |
|
167 |
|
168 def main(): |
|
169 shortargs = 'vhp:z:o:' |
|
170 longargs = ['verbose', 'help', 'percent=', 'zipfile=', 'outdir='] |
|
171 |
|
172 unzipper = unzip() |
|
173 |
|
174 try: |
|
175 opts, args = getopt.getopt(sys.argv[1:], shortargs, longargs) |
|
176 except getopt.GetoptError: |
|
177 usage() |
|
178 sys.exit(2) |
|
179 |
|
180 zipsource = "" |
|
181 zipdest = "" |
|
182 |
|
183 for o, a in opts: |
|
184 if o in ("-v", "--verbose"): |
|
185 unzipper.verbose = True |
|
186 if o in ("-p", "--percent"): |
|
187 if not unzipper.verbose == True: |
|
188 unzipper.percent = int(a) |
|
189 if o in ("-z", "--zipfile"): |
|
190 zipsource = a |
|
191 if o in ("-o", "--outdir"): |
|
192 zipdest = a |
|
193 if o in ("-h", "--help"): |
|
194 usage() |
|
195 sys.exit() |
|
196 |
|
197 if zipsource == "" or zipdest == "": |
|
198 usage() |
|
199 sys.exit() |
|
200 |
|
201 unzipper.extract(zipsource, zipdest) |
|
202 |
|
203 if __name__ == '__main__': main() |