给出两条绝对路径,例如

/var/data/stuff/xyz.dat
/var/data

如何创建一个以第二条路径为基础的相对路径?在上面的例子中,结果应该是:./stuff/xyz.dat


当前回答

ant有一个带有getRelativePath方法的FileUtils类。我自己还没有尝试过,但是值得一试。

http://javadoc.haefelinger.it/org.apache.ant/1.7.1/org/apache/tools/ant/util/FileUtils.html getRelativePath (java.io.File java.io.File)

其他回答

如果你知道第二个字符串是第一个字符串的一部分:

String s1 = "/var/data/stuff/xyz.dat";
String s2 = "/var/data";
String s3 = s1.substring(s2.length());

或者,如果你真的想把句号放在开头,就像你的例子中那样:

String s3 = ".".concat(s1.substring(s2.length()));

这里已经有很多答案了,但我发现他们并不能处理所有的情况,比如基地和目标是相同的。这个函数接受一个基本目录和一个目标路径,并返回相对路径。如果不存在相对路径,则返回目标路径。文件。分隔符是不必要的。

public static String getRelativePath (String baseDir, String targetPath) {
    String[] base = baseDir.replace('\\', '/').split("\\/");
    targetPath = targetPath.replace('\\', '/');
    String[] target = targetPath.split("\\/");

    // Count common elements and their length.
    int commonCount = 0, commonLength = 0, maxCount = Math.min(target.length, base.length);
    while (commonCount < maxCount) {
        String targetElement = target[commonCount];
        if (!targetElement.equals(base[commonCount])) break;
        commonCount++;
        commonLength += targetElement.length() + 1; // Directory name length plus slash.
    }
    if (commonCount == 0) return targetPath; // No common path element.

    int targetLength = targetPath.length();
    int dirsUp = base.length - commonCount;
    StringBuffer relative = new StringBuffer(dirsUp * 3 + targetLength - commonLength + 1);
    for (int i = 0; i < dirsUp; i++)
        relative.append("../");
    if (commonLength < targetLength) relative.append(targetPath.substring(commonLength));
    return relative.toString();
}

下面是一个从基本路径解析相对路径的方法,不管它们在相同或不同的根路径中:

public static String GetRelativePath(String path, String base){

    final String SEP = "/";

    // if base is not a directory -> return empty
    if (!base.endsWith(SEP)){
        return "";
    }

    // check if path is a file -> remove last "/" at the end of the method
    boolean isfile = !path.endsWith(SEP);

    // get URIs and split them by using the separator
    String a = "";
    String b = "";
    try {
        a = new File(base).getCanonicalFile().toURI().getPath();
        b = new File(path).getCanonicalFile().toURI().getPath();
    } catch (IOException e) {
        e.printStackTrace();
    }
    String[] basePaths = a.split(SEP);
    String[] otherPaths = b.split(SEP);

    // check common part
    int n = 0;
    for(; n < basePaths.length && n < otherPaths.length; n ++)
    {
        if( basePaths[n].equals(otherPaths[n]) == false )
            break;
    }

    // compose the new path
    StringBuffer tmp = new StringBuffer("");
    for(int m = n; m < basePaths.length; m ++)
        tmp.append(".."+SEP);
    for(int m = n; m < otherPaths.length; m ++)
    {
        tmp.append(otherPaths[m]);
        tmp.append(SEP);
    }

    // get path string
    String result = tmp.toString();

    // remove last "/" if path is a file
    if (isfile && result.endsWith(SEP)){
        result = result.substring(0,result.length()-1);
    }

    return result;
}

实际上,如果目标路径不是基路径的子路径,我的另一个答案是不成立的。

这应该有用。

public class RelativePathFinder {

    public static String getRelativePath(String targetPath, String basePath, 
       String pathSeparator) {

        // find common path
        String[] target = targetPath.split(pathSeparator);
        String[] base = basePath.split(pathSeparator);

        String common = "";
        int commonIndex = 0;
        for (int i = 0; i < target.length && i < base.length; i++) {

            if (target[i].equals(base[i])) {
                common += target[i] + pathSeparator;
                commonIndex++;
            }
        }


        String relative = "";
        // is the target a child directory of the base directory?
        // i.e., target = /a/b/c/d, base = /a/b/
        if (commonIndex == base.length) {
            relative = "." + pathSeparator + targetPath.substring(common.length());
        }
        else {
            // determine how many directories we have to backtrack
            for (int i = 1; i <= commonIndex; i++) {
                relative += ".." + pathSeparator;
            }
            relative += targetPath.substring(common.length());
        }

        return relative;
    }

    public static String getRelativePath(String targetPath, String basePath) {
        return getRelativePath(targetPath, basePath, File.pathSeparator);
    }
}

public class RelativePathFinderTest extends TestCase {

    public void testGetRelativePath() {
        assertEquals("./stuff/xyz.dat", RelativePathFinder.getRelativePath(
                "/var/data/stuff/xyz.dat", "/var/data/", "/"));
        assertEquals("../../b/c", RelativePathFinder.getRelativePath("/a/b/c",
                "/a/x/y/", "/"));
    }

}

Psuedo-code:

使用路径分隔符("/")拆分字符串 通过迭代拆分字符串的结果来找到最大的公共路径(因此在两个示例中,您最终会得到"/var/data"或"/a") 返回“。”+ whicheverPathIsLonger.substring (commonPath.length);