Java Path Relative Get getRelativePath(File source, File destination)

Here you can find the source of getRelativePath(File source, File destination)

Description

Gets a relative path from the source file to the destination

License

Open Source License

Parameter

Parameter Description
source The source file or location
destination The file to target with the relative path

Return

The relative path from the source file's directory to the destination file

Declaration

public static String getRelativePath(File source, File destination) throws IOException 

Method Source Code

//package com.java2s;
//License from project: Open Source License 

import java.io.File;

import java.io.IOException;

import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

public class Main {
    /**/*from   w w w. j  a v  a  2  s .co  m*/
     * Gets a relative path from the source file to the destination
     * 
     * @param source
     *            The source file or location
     * @param destination
     *            The file to target with the relative path
     * @return The relative path from the source file's directory to the
     *         destination file
     */
    public static String getRelativePath(File source, File destination) throws IOException {
        String sourceDir = null;
        String destDir = null;
        if (source.isDirectory()) {
            sourceDir = source.getCanonicalPath();
        } else {
            sourceDir = source.getParentFile().getCanonicalPath();
        }
        if (destination.isDirectory()) {
            destDir = destination.getCanonicalPath();
        } else {
            destDir = destination.getParentFile().getCanonicalPath();
        }

        // find the overlap in the source and dest paths
        String overlap = findOverlap(sourceDir, destDir);
        // strip off a training File.separator
        if (overlap.endsWith(File.separator)) {
            if (overlap.equals(File.separator)) {
                overlap = "";
            } else {
                overlap = overlap.substring(0, overlap.length() - File.separator.length() - 1);
            }
        }
        int overlapDirs = countChars(overlap, File.separatorChar);
        if (overlapDirs == 0) {
            // no overlap at all, return full path of destination file
            return destination.getCanonicalPath();
        }
        // difference is the number of path elements to back up before moving
        // down the tree
        int parentDirsNeeded = countChars(sourceDir, File.separatorChar) - overlapDirs;
        // difference is the number of path elements above the file to keep
        int parentDirsKept = countChars(destDir, File.separatorChar) - overlapDirs;

        // build the path
        StringBuffer relPath = new StringBuffer();
        for (int i = 0; i < parentDirsNeeded; i++) {
            relPath.append("..").append(File.separatorChar);
        }
        List<String> parentPaths = new LinkedList<String>();
        File parentDir = new File(destDir);
        for (int i = 0; i < parentDirsKept; i++) {
            parentPaths.add(parentDir.getName());
            parentDir = parentDir.getParentFile();
        }
        Collections.reverse(parentPaths);
        for (Iterator<String> i = parentPaths.iterator(); i.hasNext();) {
            relPath.append(i.next()).append(File.separatorChar);
        }
        if (!destination.isDirectory()) {
            relPath.append(destination.getName());
        }
        return relPath.toString();
    }

    private static String findOverlap(String s1, String s2) {
        // TODO: More efficient would be some kind of binary search, divide and
        // conquer
        StringBuffer overlap = new StringBuffer();
        int count = Math.min(s1.length(), s2.length());
        for (int i = 0; i < count; i++) {
            char c1 = s1.charAt(i);
            char c2 = s2.charAt(i);
            if (c1 == c2) {
                overlap.append(c1);
            } else {
                break;
            }
        }
        return overlap.toString();
    }

    /**
     * Like Object.equals, but if o1 == null && o2 == null, returns true
     * 
     * @param o1
     * @param o2
     * @return
     */
    public static boolean equals(Object o1, Object o2) {
        if (o1 == null) {
            return o2 == null;
        }
        return o1.equals(o2);
    }

    private static int countChars(String s, char c) {
        int count = 0;
        int index = -1;
        while ((index = s.indexOf(c, index + 1)) != -1) {
            count++;
        }
        return count;
    }
}

Related

  1. getRelativePath(File ref_file, File tst_file)
  2. getRelativePath(File root, File file)
  3. getRelativePath(File root, File file)
  4. getRelativePath(File root, File target, String fileSeparator)
  5. getRelativePath(File rootDirectory, File file)
  6. getRelativePath(File source, File target)
  7. getRelativePath(File src, File dst)
  8. getRelativePath(File subj, File relativeTo)
  9. getRelativePath(File target, File base)