Mercurial > dive4elements > framework
comparison artifacts-common/src/main/java/de/intevation/artifacts/common/utils/FileTools.java @ 329:666417d5781c
Inserted a new utility class FileTools to work with files.
artifacts/trunk@2584 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author | Ingo Weinzierl <ingo.weinzierl@intevation.de> |
---|---|
date | Thu, 25 Aug 2011 14:30:59 +0000 |
parents | |
children | 0723859f776f |
comparison
equal
deleted
inserted
replaced
328:1eb7863136f4 | 329:666417d5781c |
---|---|
1 /* | |
2 * Copyright (c) 2010, 2011 by Intevation GmbH | |
3 * | |
4 * This program is free software under the LGPL (>=v2.1) | |
5 * Read the file LGPL.txt coming with the software for details | |
6 * or visit http://www.gnu.org/licenses/ if it does not exist. | |
7 */ | |
8 package de.intevation.artifacts.common.utils; | |
9 | |
10 import java.io.BufferedInputStream; | |
11 import java.io.File; | |
12 import java.io.IOException; | |
13 import java.io.InputStream; | |
14 import java.io.FileInputStream; | |
15 import java.io.OutputStream; | |
16 | |
17 import java.util.Stack; | |
18 import java.util.List; | |
19 import java.util.Set; | |
20 import java.util.HashSet; | |
21 import java.util.ArrayList; | |
22 import java.util.zip.ZipEntry; | |
23 import java.util.zip.ZipOutputStream; | |
24 | |
25 import org.apache.log4j.Logger; | |
26 | |
27 import java.security.MessageDigest; | |
28 import java.security.NoSuchAlgorithmException; | |
29 | |
30 public class FileTools | |
31 { | |
32 private static Logger log = Logger.getLogger(FileTools.class); | |
33 | |
34 public static final String DIGEST = | |
35 System.getProperty("artifacts.common.file.cmp.digest", "MD5"); | |
36 | |
37 private FileTools() { | |
38 } | |
39 | |
40 | |
41 public static File getDirectory(String path, String name) { | |
42 if (path == null || name == null) { | |
43 return null; | |
44 } | |
45 | |
46 File dir = new File(path, name); | |
47 | |
48 if (!dir.exists()) { | |
49 log.debug( | |
50 "Directory '" + dir.getAbsolutePath() + "' doesn't " + | |
51 "exist. Try to create it."); | |
52 | |
53 return dir.mkdir() ? dir : null; | |
54 } | |
55 else { | |
56 return dir.isDirectory() ? dir : null; | |
57 } | |
58 } | |
59 | |
60 public static File repair(File file) { | |
61 file = file.getAbsoluteFile(); | |
62 if (file.exists()) { | |
63 return file; | |
64 } | |
65 Stack<String> parts = new Stack<String>(); | |
66 File curr = file; | |
67 while (curr != null) { | |
68 String name = curr.getName(); | |
69 if (name.length() > 0) { | |
70 parts.push(curr.getName()); | |
71 } | |
72 curr = curr.getParentFile(); | |
73 } | |
74 | |
75 curr = null; | |
76 OUTER: while (!parts.isEmpty()) { | |
77 String f = parts.pop(); | |
78 log.debug("fixing: '" + f + "'"); | |
79 if (curr == null) { | |
80 // XXX: Not totaly correct because there | |
81 // more than one root on none unix systems. | |
82 for (File root: File.listRoots()) { | |
83 File [] files = root.listFiles(); | |
84 if (files == null) { | |
85 log.warn("cannot list '" + root); | |
86 continue; | |
87 } | |
88 for (File candidate: files) { | |
89 if (candidate.getName().equalsIgnoreCase(f)) { | |
90 curr = new File(root, candidate.getName()); | |
91 continue OUTER; | |
92 } | |
93 } | |
94 } | |
95 break; | |
96 } | |
97 else { | |
98 File [] files = curr.listFiles(); | |
99 if (files == null) { | |
100 log.warn("cannot list: '" + curr + "'"); | |
101 return file; | |
102 } | |
103 for (File candidate: files) { | |
104 if (candidate.getName().equalsIgnoreCase(f)) { | |
105 curr = new File(curr, candidate.getName()); | |
106 continue OUTER; | |
107 } | |
108 } | |
109 curr = null; | |
110 break; | |
111 } | |
112 } | |
113 | |
114 if (curr == null) { | |
115 log.warn("cannot repair path '" + file + "'"); | |
116 return file; | |
117 } | |
118 | |
119 return curr; | |
120 } | |
121 | |
122 public static class HashedFile | |
123 implements Comparable<HashedFile> | |
124 { | |
125 protected File file; | |
126 protected long length; | |
127 protected byte [] hash; | |
128 | |
129 public HashedFile(File file) { | |
130 this.file = file; | |
131 length = file.length(); | |
132 } | |
133 | |
134 public File getFile() { | |
135 return file; | |
136 } | |
137 | |
138 protected byte [] getHash() { | |
139 if (hash == null) { | |
140 InputStream in = null; | |
141 | |
142 try { | |
143 in = new FileInputStream(file); | |
144 | |
145 MessageDigest digest = MessageDigest.getInstance(DIGEST); | |
146 | |
147 byte [] buf = new byte[40*1024]; | |
148 int r; | |
149 | |
150 while ((r = in.read(buf)) >= 0) { | |
151 digest.update(buf, 0, r); | |
152 } | |
153 | |
154 hash = digest.digest(); | |
155 } | |
156 catch (IOException ioe) { | |
157 log.error(ioe); | |
158 hash = new byte[0]; | |
159 } | |
160 catch (NoSuchAlgorithmException nsae) { | |
161 log.error(nsae); | |
162 hash = new byte[0]; | |
163 } | |
164 finally { | |
165 if (in != null) { | |
166 try { | |
167 in.close(); | |
168 } | |
169 catch (IOException ioe) { | |
170 log.error(ioe); | |
171 } | |
172 } | |
173 } | |
174 } | |
175 return hash; | |
176 } | |
177 | |
178 @Override | |
179 public int compareTo(HashedFile other) { | |
180 if (length < other.length) return -1; | |
181 if (length > other.length) return +1; | |
182 return compare(getHash(), other.getHash()); | |
183 } | |
184 | |
185 private static int compare(byte [] a, byte [] b) { | |
186 if (a.length < b.length) return -1; | |
187 if (a.length > b.length) return +1; | |
188 for (int i = 0; i < a.length; ++i) { | |
189 int x = a[i] & 0xff; | |
190 int y = b[i] & 0xff; | |
191 if (x < y) return -1; | |
192 if (x > y) return +1; | |
193 } | |
194 return 0; | |
195 } | |
196 | |
197 @Override | |
198 public boolean equals(Object other) { | |
199 return other instanceof HashedFile | |
200 && ((HashedFile)other).compareTo(this) == 0; | |
201 } | |
202 | |
203 @Override | |
204 public int hashCode() { | |
205 return (int)(length ^ (length >>> 32)); | |
206 } | |
207 } // class HashedFile | |
208 | |
209 public static List<File> uniqueFiles(List<File> files) { | |
210 | |
211 Set<HashedFile> set = new HashSet<HashedFile>(); | |
212 | |
213 for (File file: files) { | |
214 if (!set.add(new HashedFile(file))) { | |
215 log.warn("file '" + file + "' is a duplicate."); | |
216 } | |
217 } | |
218 | |
219 ArrayList<File> out = new ArrayList<File>(set.size()); | |
220 for (HashedFile hf: set) { | |
221 out.add(hf.file); | |
222 } | |
223 | |
224 return out; | |
225 } | |
226 | |
227 public interface FileVisitor { | |
228 boolean visit(File file); | |
229 } // Visitor | |
230 | |
231 public static void walkTree(File root, FileVisitor visitor) { | |
232 | |
233 Stack<File> stack = new Stack<File>(); | |
234 | |
235 stack.push(root); | |
236 | |
237 while (!stack.isEmpty()) { | |
238 File current = stack.pop(); | |
239 if (!visitor.visit(current)) break; | |
240 if (current.isDirectory()) { | |
241 File [] subs = current.listFiles(); | |
242 if (subs != null) { | |
243 for (File f: subs) { | |
244 stack.push(f); | |
245 } | |
246 } | |
247 } | |
248 } | |
249 } | |
250 | |
251 /** | |
252 * Deletes everything in a directory. | |
253 * | |
254 * @param dir The directory. | |
255 */ | |
256 public final static void deleteContent(File dir) { | |
257 if (dir == null || !dir.isDirectory()) { | |
258 return; | |
259 } | |
260 | |
261 File[] files = dir.listFiles(); | |
262 if (files != null) { | |
263 for (File file: files) { | |
264 deleteRecursive(file); | |
265 } | |
266 } | |
267 | |
268 return; | |
269 } | |
270 | |
271 /** | |
272 * Delete <i>file</i> and everything in <i>file</i> if it is a directory. | |
273 * | |
274 * @param file The file or directory. | |
275 * @return true, if deletion was successful - otherwise false. | |
276 */ | |
277 public final static boolean deleteRecursive(File file) { | |
278 | |
279 if (file == null) { | |
280 return false; | |
281 } | |
282 | |
283 if (file.isDirectory()) { | |
284 File [] files = file.listFiles(); | |
285 if (files != null) { | |
286 for (File sub: files) { | |
287 if (!deleteRecursive(sub)) { | |
288 return false; | |
289 } | |
290 } | |
291 } | |
292 } | |
293 | |
294 return file.delete(); | |
295 } | |
296 | |
297 /** | |
298 * Put the given file or directory into a zip archive. | |
299 * | |
300 * @param file The file or directory. | |
301 * @param outputStream The stream to write the archive to. | |
302 * @throws IOException if an error occured while zip creation or writing to | |
303 * output stream. | |
304 */ | |
305 public static void createZipArchive( | |
306 File file, | |
307 OutputStream outputStream | |
308 ) | |
309 throws IOException | |
310 { | |
311 ZipOutputStream out = new ZipOutputStream(outputStream); | |
312 | |
313 if (file.isFile()) { | |
314 copyFileToZip("", file, out); | |
315 } | |
316 else if (file.isDirectory()) { | |
317 | |
318 Stack<PrefixDir> stack = new Stack<PrefixDir>(); | |
319 stack.push(new PrefixDir(file.getName() + "/", file)); | |
320 | |
321 while (!stack.isEmpty()) { | |
322 PrefixDir pd = stack.pop(); | |
323 | |
324 ZipEntry dirEntry = new ZipEntry(pd.prefix); | |
325 out.putNextEntry(dirEntry); | |
326 out.closeEntry(); | |
327 | |
328 File [] files = pd.dir.listFiles(); | |
329 if (files != null) { | |
330 for (File sub: files) { | |
331 if (sub.isDirectory()) { | |
332 stack.push(new PrefixDir( | |
333 pd.prefix + sub.getName() + "/", | |
334 sub)); | |
335 } | |
336 else if (sub.isFile()) { | |
337 copyFileToZip(pd.prefix, sub, out); | |
338 } | |
339 } | |
340 } | |
341 } | |
342 } | |
343 | |
344 out.finish(); | |
345 } | |
346 | |
347 /** | |
348 * A class representing a directory with a prefix. | |
349 */ | |
350 private static final class PrefixDir { | |
351 | |
352 String prefix; | |
353 File dir; | |
354 | |
355 public PrefixDir(String prefix, File dir) { | |
356 this.prefix = prefix; | |
357 this.dir = dir; | |
358 } | |
359 | |
360 } // class PrefixDir | |
361 | |
362 /** | |
363 * Write a file to zip archive. | |
364 * | |
365 * @param prefix A prefix. | |
366 * @param file The file. | |
367 * @param out The output stream. | |
368 * @throws IOException if an error occured while writing to zip output | |
369 * stream. | |
370 */ | |
371 private static void copyFileToZip( | |
372 String prefix, | |
373 File file, | |
374 ZipOutputStream out | |
375 ) | |
376 throws IOException | |
377 { | |
378 String entryName = prefix + file.getName(); | |
379 ZipEntry entry = new ZipEntry(entryName); | |
380 out.putNextEntry(entry); | |
381 InputStream in = null; | |
382 try { | |
383 in = | |
384 new BufferedInputStream( | |
385 new FileInputStream(file), 20*1024); | |
386 | |
387 byte [] buf = new byte[2048]; | |
388 | |
389 int r; | |
390 while ((r = in.read(buf)) > 0) { | |
391 out.write(buf, 0, r); | |
392 } | |
393 } | |
394 finally { | |
395 if (in != null) { | |
396 try { in.close(); } | |
397 catch (IOException ioe) {} | |
398 } | |
399 } | |
400 out.closeEntry(); | |
401 } | |
402 } | |
403 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : |