view flys-backend/src/main/java/de/intevation/flys/utils/FileTools.java @ 1213:cc88db4a5b34

Added method walkTree() to traverse a directory tree. To be reused in HYK parser. flys-backend/trunk@2339 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Fri, 15 Jul 2011 15:36:59 +0000
parents 7121a40671ff
children
line wrap: on
line source
package de.intevation.flys.utils;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.FileInputStream;

import java.util.Stack;
import java.util.List;
import java.util.Set;
import java.util.HashSet;
import java.util.ArrayList;

import org.apache.log4j.Logger;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class FileTools
{
    private static Logger log = Logger.getLogger(FileTools.class);

    public static final String DIGEST =
        System.getProperty("flys.backend.file.cmp.digest", "MD5");

    private FileTools() {
    }

    public static File repair(File file) {
        file = file.getAbsoluteFile();
        if (file.exists()) {
            return file;
        }
        Stack<String> parts = new Stack<String>();
        File curr = file;
        while (curr != null) {
            String name = curr.getName();
            if (name.length() > 0) {
                parts.push(curr.getName());
            }
            curr = curr.getParentFile();
        }

        curr = null;
        OUTER: while (!parts.isEmpty()) {
            String f = parts.pop();
            log.debug("fixing: '" + f + "'");
            if (curr == null) {
                // XXX: Not totaly correct because there
                // more than one root on none unix systems.
                for (File root: File.listRoots()) {
                    File [] files = root.listFiles();
                    if (files == null) {
                        log.warn("cannot list '" + root);
                        continue;
                    }
                    for (File candidate: files) {
                        if (candidate.getName().equalsIgnoreCase(f)) {
                            curr = new File(root, candidate.getName());
                            continue OUTER;
                        }
                    }
                }
                break;
            }
            else {
                File [] files = curr.listFiles();
                if (files == null) {
                    log.warn("cannot list: '" + curr + "'");
                    return file;
                }
                for (File candidate: files) {
                    if (candidate.getName().equalsIgnoreCase(f)) {
                        curr = new File(curr, candidate.getName());
                        continue OUTER;
                    }
                }
                curr = null;
                break;
            }
        }

        if (curr == null) {
            log.warn("cannot repair path '" + file + "'");
            return file;
        }

        return curr;
    }

    public static class HashedFile 
    implements Comparable<HashedFile>
    {
        protected File    file;
        protected long    length;
        protected byte [] hash;

        public HashedFile(File file) {
            this.file = file;
            length = file.length();
        }

        public File getFile() {
            return file;
        }

        protected byte [] getHash() {
            if (hash == null) {
                InputStream in = null;

                try {
                    in = new FileInputStream(file);

                    MessageDigest digest = MessageDigest.getInstance(DIGEST);

                    byte [] buf = new byte[40*1024];
                    int r;

                    while ((r = in.read(buf)) >= 0) {
                        digest.update(buf, 0, r);
                    }

                    hash = digest.digest();
                }
                catch (IOException ioe) {
                    log.error(ioe);
                    hash = new byte[0];
                }
                catch (NoSuchAlgorithmException nsae) {
                    log.error(nsae);
                    hash = new byte[0];
                }
                finally {
                    if (in != null) {
                        try {
                            in.close();
                        }
                        catch (IOException ioe) {
                            log.error(ioe);
                        }
                    }
                }
            }
            return hash;
        }

        @Override
        public int compareTo(HashedFile other) {
            if (length < other.length) return -1;
            if (length > other.length) return +1;
            return compare(getHash(), other.getHash());
        }

        private static int compare(byte [] a, byte [] b) {
            if (a.length < b.length) return -1;
            if (a.length > b.length) return +1;
            for (int i = 0; i < a.length; ++i) {
                int x = a[i] & 0xff;
                int y = b[i] & 0xff;
                if (x < y) return -1;
                if (x > y) return +1;
            }
            return 0;
        }

        @Override
        public boolean equals(Object other) {
            return other instanceof HashedFile 
                && ((HashedFile)other).compareTo(this) == 0;
        }

        @Override
        public int hashCode() {
            return (int)(length ^ (length >>> 32));
        }
    } // class HashedFile

    public static List<File> uniqueFiles(List<File> files) {

        Set<HashedFile> set = new HashSet<HashedFile>();

        for (File file: files) {
            if (!set.add(new HashedFile(file))) {
                log.warn("file '" + file + "' is a duplicate.");
            }
        }

        ArrayList<File> out = new ArrayList<File>(set.size());
        for (HashedFile hf: set) {
            out.add(hf.file);
        }

        return out;
    }

    public interface FileVisitor {
        boolean visit(File file);
    } // Visitor

    public static void walkTree(File root, FileVisitor visitor) {

        Stack<File> stack = new Stack<File>();

        stack.push(root);

        while (!stack.isEmpty()) {
            File current = stack.pop();
            if (!visitor.visit(current)) break;
            if (current.isDirectory()) {
                File [] subs = current.listFiles();
                if (subs != null) {
                    for (File f: subs) {
                        stack.push(f);
                    }
                }
            }
        }
    }
}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org