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 :

http://dive4elements.wald.intevation.org