Mercurial > dive4elements > framework
comparison artifacts-common/src/main/java/org/dive4elements/artifacts/common/utils/FileTools.java @ 472:783cc1b6b615
Moved directories to org.dive4elements
author | Sascha L. Teichmann <teichmann@intevation.de> |
---|---|
date | Thu, 25 Apr 2013 10:53:15 +0200 |
parents | artifacts-common/src/main/java/de/intevation/artifacts/common/utils/FileTools.java@5c07601fe60e |
children | 415df0fc4fa1 |
comparison
equal
deleted
inserted
replaced
471:1a87cb24a446 | 472:783cc1b6b615 |
---|---|
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.FileOutputStream; | |
16 import java.io.OutputStream; | |
17 import java.io.BufferedOutputStream; | |
18 import java.nio.channels.FileChannel; | |
19 | |
20 import java.util.Deque; | |
21 import java.util.ArrayDeque; | |
22 import java.util.List; | |
23 import java.util.Set; | |
24 import java.util.HashSet; | |
25 import java.util.ArrayList; | |
26 import java.util.Enumeration; | |
27 import java.util.zip.ZipFile; | |
28 import java.util.zip.ZipEntry; | |
29 import java.util.zip.ZipOutputStream; | |
30 | |
31 import org.apache.log4j.Logger; | |
32 | |
33 import java.security.MessageDigest; | |
34 import java.security.NoSuchAlgorithmException; | |
35 | |
36 public class FileTools | |
37 { | |
38 private static Logger log = Logger.getLogger(FileTools.class); | |
39 | |
40 public static final String DIGEST = | |
41 System.getProperty("artifacts.common.file.cmp.digest", "MD5"); | |
42 | |
43 private FileTools() { | |
44 } | |
45 | |
46 | |
47 /** Remove everything after dot from name. */ | |
48 public static final String removeExtension(String name) { | |
49 int index = name.lastIndexOf('.'); | |
50 return index == -1 | |
51 ? name | |
52 : name.substring(0, index); | |
53 } | |
54 | |
55 | |
56 public static File getDirectory(String path, String name) { | |
57 if (path == null || name == null) { | |
58 return null; | |
59 } | |
60 | |
61 File dir = new File(path, name); | |
62 | |
63 if (!dir.exists()) { | |
64 log.debug( | |
65 "Directory '" + dir.getAbsolutePath() + "' doesn't " + | |
66 "exist. Try to create it."); | |
67 | |
68 return dir.mkdir() ? dir : null; | |
69 } | |
70 else { | |
71 return dir.isDirectory() ? dir : null; | |
72 } | |
73 } | |
74 | |
75 public static File repair(File file) { | |
76 file = file.getAbsoluteFile(); | |
77 if (file.exists()) { | |
78 return file; | |
79 } | |
80 Deque<String> parts = new ArrayDeque<String>(); | |
81 File curr = file; | |
82 while (curr != null) { | |
83 String name = curr.getName(); | |
84 if (name.length() > 0) { | |
85 parts.push(curr.getName()); | |
86 } | |
87 curr = curr.getParentFile(); | |
88 } | |
89 | |
90 curr = null; | |
91 OUTER: while (!parts.isEmpty()) { | |
92 String f = parts.pop(); | |
93 log.debug("fixing: '" + f + "'"); | |
94 if (f.equals(".") || f.equals("..")) { | |
95 // No need to fix . or .. | |
96 continue; | |
97 } | |
98 if (curr == null) { | |
99 // XXX: Not totaly correct because there | |
100 // more than one root on none unix systems. | |
101 for (File root: File.listRoots()) { | |
102 File [] files = root.listFiles(); | |
103 if (files == null) { | |
104 log.warn("cannot list '" + root); | |
105 continue; | |
106 } | |
107 for (File candidate: files) { | |
108 if (candidate.getName().equalsIgnoreCase(f)) { | |
109 curr = new File(root, candidate.getName()); | |
110 continue OUTER; | |
111 } | |
112 } | |
113 } | |
114 break; | |
115 } | |
116 else { | |
117 File [] files = curr.listFiles(); | |
118 if (files == null) { | |
119 log.warn("cannot list: '" + curr + "'"); | |
120 return file; | |
121 } | |
122 for (File candidate: files) { | |
123 if (candidate.getName().equalsIgnoreCase(f)) { | |
124 curr = new File(curr, candidate.getName()); | |
125 continue OUTER; | |
126 } | |
127 } | |
128 curr = null; | |
129 break; | |
130 } | |
131 } | |
132 | |
133 if (curr == null) { | |
134 log.warn("cannot repair path '" + file + "'"); | |
135 return file; | |
136 } | |
137 | |
138 return curr; | |
139 } | |
140 | |
141 /** Object that can calculate hash of file, compare two hashed files etc. */ | |
142 public static class HashedFile | |
143 implements Comparable<HashedFile> | |
144 { | |
145 protected File file; | |
146 protected long length; | |
147 protected byte [] hash; | |
148 | |
149 public HashedFile(File file) { | |
150 this.file = file; | |
151 length = file.length(); | |
152 } | |
153 | |
154 public File getFile() { | |
155 return file; | |
156 } | |
157 | |
158 protected byte [] getHash() { | |
159 if (hash == null) { | |
160 InputStream in = null; | |
161 | |
162 try { | |
163 in = new FileInputStream(file); | |
164 | |
165 MessageDigest digest = MessageDigest.getInstance(DIGEST); | |
166 | |
167 byte [] buf = new byte[40*1024]; | |
168 int r; | |
169 | |
170 while ((r = in.read(buf)) >= 0) { | |
171 digest.update(buf, 0, r); | |
172 } | |
173 | |
174 hash = digest.digest(); | |
175 } | |
176 catch (IOException ioe) { | |
177 log.error(ioe); | |
178 hash = new byte[0]; | |
179 } | |
180 catch (NoSuchAlgorithmException nsae) { | |
181 log.error(nsae); | |
182 hash = new byte[0]; | |
183 } | |
184 finally { | |
185 if (in != null) { | |
186 try { | |
187 in.close(); | |
188 } | |
189 catch (IOException ioe) { | |
190 log.error(ioe); | |
191 } | |
192 } | |
193 } | |
194 } | |
195 return hash; | |
196 } | |
197 | |
198 @Override | |
199 public int compareTo(HashedFile other) { | |
200 if (length < other.length) return -1; | |
201 if (length > other.length) return +1; | |
202 return compare(getHash(), other.getHash()); | |
203 } | |
204 | |
205 private static int compare(byte [] a, byte [] b) { | |
206 if (a.length < b.length) return -1; | |
207 if (a.length > b.length) return +1; | |
208 for (int i = 0; i < a.length; ++i) { | |
209 int x = a[i] & 0xff; | |
210 int y = b[i] & 0xff; | |
211 if (x < y) return -1; | |
212 if (x > y) return +1; | |
213 } | |
214 return 0; | |
215 } | |
216 | |
217 @Override | |
218 public boolean equals(Object other) { | |
219 return other instanceof HashedFile | |
220 && ((HashedFile)other).compareTo(this) == 0; | |
221 } | |
222 | |
223 @Override | |
224 public int hashCode() { | |
225 return (int)(length ^ (length >>> 32)); | |
226 } | |
227 } // class HashedFile | |
228 | |
229 public static List<File> uniqueFiles(List<File> files) { | |
230 | |
231 Set<HashedFile> set = new HashSet<HashedFile>(); | |
232 | |
233 for (File file: files) { | |
234 if (!set.add(new HashedFile(file))) { | |
235 log.warn("file '" + file + "' is a duplicate."); | |
236 } | |
237 } | |
238 | |
239 ArrayList<File> out = new ArrayList<File>(set.size()); | |
240 for (HashedFile hf: set) { | |
241 out.add(hf.file); | |
242 } | |
243 | |
244 return out; | |
245 } | |
246 | |
247 public interface FileVisitor { | |
248 boolean visit(File file); | |
249 } // Visitor | |
250 | |
251 public static void walkTree(File root, FileVisitor visitor) { | |
252 | |
253 Deque<File> stack = new ArrayDeque<File>(); | |
254 | |
255 stack.push(root); | |
256 | |
257 while (!stack.isEmpty()) { | |
258 File current = stack.pop(); | |
259 if (!visitor.visit(current)) break; | |
260 if (current.isDirectory()) { | |
261 File [] subs = current.listFiles(); | |
262 if (subs != null) { | |
263 for (File f: subs) { | |
264 stack.push(f); | |
265 } | |
266 } | |
267 } | |
268 } | |
269 } | |
270 | |
271 /** | |
272 * Deletes everything in a directory. | |
273 * | |
274 * @param dir The directory. | |
275 */ | |
276 public final static void deleteContent(File dir) { | |
277 if (dir == null || !dir.isDirectory()) { | |
278 return; | |
279 } | |
280 | |
281 File[] files = dir.listFiles(); | |
282 if (files != null) { | |
283 for (File file: files) { | |
284 deleteRecursive(file); | |
285 } | |
286 } | |
287 | |
288 return; | |
289 } | |
290 | |
291 /** | |
292 * Delete <i>file</i> and everything in <i>file</i> if it is a directory. | |
293 * | |
294 * @param file The file or directory. | |
295 * @return true, if deletion was successful - otherwise false. | |
296 */ | |
297 public final static boolean deleteRecursive(File file) { | |
298 | |
299 if (file == null) { | |
300 return false; | |
301 } | |
302 | |
303 if (file.isDirectory()) { | |
304 File [] files = file.listFiles(); | |
305 if (files != null) { | |
306 for (File sub: files) { | |
307 if (!deleteRecursive(sub)) { | |
308 return false; | |
309 } | |
310 } | |
311 } | |
312 } | |
313 | |
314 return file.delete(); | |
315 } | |
316 | |
317 /** | |
318 * Put the given file or directory into a zip archive. | |
319 * | |
320 * @param file The file or directory. | |
321 * @param outputStream The stream to write the archive to. | |
322 * @throws IOException if an error occured while zip creation or writing to | |
323 * output stream. | |
324 */ | |
325 public static void createZipArchive( | |
326 File file, | |
327 OutputStream outputStream | |
328 ) | |
329 throws IOException | |
330 { | |
331 ZipOutputStream out = new ZipOutputStream(outputStream); | |
332 | |
333 if (file.isFile()) { | |
334 copyFileToZip("", file, out); | |
335 } | |
336 else if (file.isDirectory()) { | |
337 | |
338 Deque<PrefixDir> stack = new ArrayDeque<PrefixDir>(); | |
339 stack.push(new PrefixDir(file.getName() + "/", file)); | |
340 | |
341 while (!stack.isEmpty()) { | |
342 PrefixDir pd = stack.pop(); | |
343 | |
344 ZipEntry dirEntry = new ZipEntry(pd.prefix); | |
345 out.putNextEntry(dirEntry); | |
346 out.closeEntry(); | |
347 | |
348 File [] files = pd.dir.listFiles(); | |
349 if (files != null) { | |
350 for (File sub: files) { | |
351 if (sub.isDirectory()) { | |
352 stack.push(new PrefixDir( | |
353 pd.prefix + sub.getName() + "/", | |
354 sub)); | |
355 } | |
356 else if (sub.isFile()) { | |
357 copyFileToZip(pd.prefix, sub, out); | |
358 } | |
359 } | |
360 } | |
361 } | |
362 } | |
363 | |
364 out.finish(); | |
365 } | |
366 | |
367 | |
368 public static void extractArchive(File archive, File destDir) | |
369 throws IOException { | |
370 if (!destDir.exists()) { | |
371 destDir.mkdir(); | |
372 } | |
373 | |
374 ZipFile zipFile = new ZipFile(archive); | |
375 try { | |
376 Enumeration<? extends ZipEntry> entries = zipFile.entries(); | |
377 | |
378 byte [] buffer = new byte[16384]; | |
379 | |
380 while (entries.hasMoreElements()) { | |
381 ZipEntry entry = entries.nextElement(); | |
382 | |
383 String entryFileName = entry.getName(); | |
384 | |
385 File dir = buildDirectoryHierarchyFor(entryFileName, destDir); | |
386 if (!dir.exists()) { | |
387 dir.mkdirs(); | |
388 } | |
389 | |
390 if (!entry.isDirectory()) { | |
391 BufferedInputStream bis = new BufferedInputStream( | |
392 zipFile.getInputStream(entry)); | |
393 try { | |
394 BufferedOutputStream bos = new BufferedOutputStream( | |
395 new FileOutputStream(new File(destDir, entryFileName))); | |
396 | |
397 try { | |
398 int len; | |
399 while ((len = bis.read(buffer)) > 0) { | |
400 bos.write(buffer, 0, len); | |
401 } | |
402 bos.flush(); | |
403 } | |
404 finally { | |
405 bos.close(); | |
406 } | |
407 } | |
408 finally { | |
409 bis.close(); | |
410 } | |
411 } // is file | |
412 } | |
413 } | |
414 finally { | |
415 zipFile.close(); | |
416 } | |
417 } | |
418 | |
419 private static File buildDirectoryHierarchyFor( | |
420 String entryName, | |
421 File destDir) | |
422 { | |
423 int lastIndex = entryName.lastIndexOf('/'); | |
424 String internalPathToEntry = entryName.substring(0, lastIndex + 1); | |
425 return new File(destDir, internalPathToEntry); | |
426 } | |
427 | |
428 /** | |
429 * A class representing a directory with a prefix. | |
430 */ | |
431 private static final class PrefixDir { | |
432 | |
433 String prefix; | |
434 File dir; | |
435 | |
436 public PrefixDir(String prefix, File dir) { | |
437 this.prefix = prefix; | |
438 this.dir = dir; | |
439 } | |
440 | |
441 } // class PrefixDir | |
442 | |
443 /** | |
444 * Write a file to zip archive. | |
445 * | |
446 * @param prefix A prefix. | |
447 * @param file The file. | |
448 * @param out The output stream. | |
449 * @throws IOException if an error occured while writing to zip output | |
450 * stream. | |
451 */ | |
452 private static void copyFileToZip( | |
453 String prefix, | |
454 File file, | |
455 ZipOutputStream out | |
456 ) | |
457 throws IOException | |
458 { | |
459 String entryName = prefix + file.getName(); | |
460 ZipEntry entry = new ZipEntry(entryName); | |
461 out.putNextEntry(entry); | |
462 InputStream in = null; | |
463 try { | |
464 in = | |
465 new BufferedInputStream( | |
466 new FileInputStream(file), 20*1024); | |
467 | |
468 byte [] buf = new byte[2048]; | |
469 | |
470 int r; | |
471 while ((r = in.read(buf)) > 0) { | |
472 out.write(buf, 0, r); | |
473 } | |
474 } | |
475 finally { | |
476 if (in != null) { | |
477 try { in.close(); } | |
478 catch (IOException ioe) {} | |
479 } | |
480 } | |
481 out.closeEntry(); | |
482 } | |
483 | |
484 | |
485 /** | |
486 * Copies a <i>src</i> file to <i>target</i>. | |
487 * | |
488 * @param src A file (not a directory) that should be copied. | |
489 * @param target The destination. This might be a file or a directory. | |
490 * | |
491 * @return true, if <i>src</i> has been successfully copied; otherwise | |
492 * false. | |
493 */ | |
494 public static boolean copyFile(File src, File target) | |
495 throws IOException | |
496 { | |
497 if (src == null || !src.exists()) { | |
498 log.warn("Source file does not exist!"); | |
499 return false; | |
500 } | |
501 | |
502 if (!src.canRead()) { | |
503 log.warn("Cannot read Source file!"); | |
504 return false; | |
505 } | |
506 | |
507 if (src.isDirectory()) { | |
508 log.warn("Source is a directory!"); | |
509 return false; | |
510 } | |
511 | |
512 if (target.isDirectory()) { | |
513 target = new File(target, src.getName()); | |
514 } | |
515 | |
516 FileInputStream in = null; | |
517 FileOutputStream out = null; | |
518 | |
519 try { | |
520 in = new FileInputStream(src); | |
521 out = new FileOutputStream(target); | |
522 | |
523 FileChannel inChannel = in.getChannel(); | |
524 FileChannel outChannel = out.getChannel(); | |
525 | |
526 inChannel.transferTo(0l, inChannel.size(), outChannel); | |
527 | |
528 return true; | |
529 } | |
530 catch (IOException ioe) { | |
531 log.warn(ioe, ioe); | |
532 } | |
533 finally { | |
534 if (in != null) { | |
535 try { | |
536 in.close(); | |
537 } | |
538 catch (IOException ioe) { /* do nothing here */ } | |
539 } | |
540 | |
541 if (out != null) { | |
542 try { | |
543 out.close(); | |
544 } | |
545 catch (IOException ioe) { /* do nothing here */ } | |
546 } | |
547 } | |
548 | |
549 return false; | |
550 } | |
551 | |
552 | |
553 /** | |
554 * Copies a directory <i>source</i> to a destination path <i>dest</i>. | |
555 * | |
556 * @param source A directory that should be copied. | |
557 * @param dest A destination directory which is created if it is not | |
558 * existing yet. | |
559 * | |
560 * @return true, if the directory has been successfully copied; otherwise | |
561 * false. | |
562 */ | |
563 public static boolean copyDirectory(final File source, final File dest) { | |
564 if (source == null || !source.exists()) { | |
565 log.warn("Source directory does not exist!"); | |
566 return false; | |
567 } | |
568 | |
569 if (!source.isDirectory()) { | |
570 log.warn("Source is not a directory!"); | |
571 return false; | |
572 } | |
573 | |
574 if (dest == null) { | |
575 log.warn("Destination directory is null!"); | |
576 return false; | |
577 } | |
578 | |
579 if (!dest.exists()) { | |
580 if (!dest.mkdir()) { | |
581 log.warn("Cannot create destination directory!"); | |
582 return false; | |
583 } | |
584 } | |
585 | |
586 File[] children = source.listFiles(); | |
587 int failed = 0; | |
588 | |
589 if (children != null && children.length > 0) { | |
590 for (File child: children) { | |
591 if (child.isFile()) { | |
592 try { | |
593 if (!copyFile(child, dest)) { | |
594 failed++; | |
595 } | |
596 } | |
597 catch (IOException ioe) { | |
598 log.warn(ioe, ioe); | |
599 failed++; | |
600 } | |
601 } | |
602 else if (child.isDirectory()) { | |
603 copyDirectory(child, new File(dest, child.getName())); | |
604 } | |
605 } | |
606 } | |
607 | |
608 log.debug("Failed to copy " + failed + " files."); | |
609 | |
610 return true; | |
611 } | |
612 } | |
613 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : |