Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Compute relative path from a directory to other file or directory.
/*
* by Shigeru KANEMOTO at SWITCHSCIENCE.
*/
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
class RelativePath {
public static String relativePath(String origin, String target) {
try {
origin = (new File(origin)).getCanonicalPath();
target = (new File(target)).getCanonicalPath();
} catch (IOException e) {
return null;
}
if (System.getProperty("os.name").indexOf("Windows") != -1) {
if (origin.startsWith("\\\\") || target.startsWith("\\\\")) {
// Windows UNC path not supported.
return null;
}
char originLetter = origin.charAt(0);
char targetLetter = target.charAt(0);
if (Character.isLetter(originLetter) && Character.isLetter(targetLetter)) {
// Windows only
if (originLetter != targetLetter) {
// Drive letters differ
return null;
}
}
}
final String[] originArray = splitBySeparator(origin);
final String[] targetArray = splitBySeparator(target);
final int maxCommonComponents = Math.min(originArray.length,
targetArray.length);
int commonComponents = 0;
while (commonComponents < maxCommonComponents
&& originArray[commonComponents]
.equals(targetArray[commonComponents])) {
commonComponents++;
}
final int ancestors = originArray.length - commonComponents;
final int descendants = targetArray.length - commonComponents;
final StringBuilder sb = new StringBuilder();
for (int i = 0; i < ancestors; i++) {
sb.append("..").append(File.separator);
}
for (int i = 0; i < descendants; i++) {
sb.append(targetArray[commonComponents + i]).append(File.separator);
}
if (sb.length() != 0) {
sb.setLength(sb.length() - File.separator.length());
}
if (sb.length() == 0) {
return ".";
}
return sb.toString();
}
private static String[] splitBySeparator(String path) {
final StringTokenizer tk = new StringTokenizer(path, File.separator,
false);
final List<String> components = new ArrayList<String>();
while (tk.hasMoreTokens()) {
components.add(tk.nextToken());
}
return components.toArray(new String[components.size()]);
}
}
import java.io.File;
import java.io.IOException;
public class RelativePath0 {
public static String relativePath(String origin, String target) {
try {
origin = (new File(origin)).getCanonicalPath();
target = (new File(target)).getCanonicalPath();
} catch (IOException e) {
return null;
}
if (origin.equals(target)) {
// origin and target is identical.
return ".";
}
if (origin.equals(File.separator)) {
// origin is root.
return target.substring(File.separator.length());
}
if (System.getProperty("os.name").indexOf("Windows") != -1) {
if (origin.startsWith("\\\\") || target.startsWith("\\\\")) {
// Windows UNC path not supported.
return null;
}
char originLetter = origin.charAt(0);
char targetLetter = target.charAt(0);
if (Character.isLetter(originLetter)
&& Character.isLetter(targetLetter)) {
// Windows only
if (originLetter != targetLetter) {
// Drive letters differ
return null;
}
}
}
String relative = "";
while (!target.startsWith(origin + File.separator)) {
origin = (new File(origin)).getParent();
if (origin.equals(File.separator))
origin = "";
relative += "..";
relative += File.separator;
}
return relative + target.substring(origin.length() + 1);
}
}
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import java.io.File;
import org.junit.Test;
public class RelativePathTest {
String mInOrigin;
String mInTarget;
String mExpectedRelativePath;
String mActualRelativePath;
@Test
public void test1() {
mInOrigin = "/abc";
mInTarget = "/abc/def.txt";
senario();
verify();
System.out.println(mExpectedRelativePath);
}
@Test
public void test2() {
mInOrigin = "/abc";
mInTarget = "/def/ghi.txt";
senario();
verify();
}
@Test
public void test3() {
mInOrigin = "/abc/def";
mInTarget = "/abc/def.txt";
senario();
verify();
}
@Test
public void test4() {
mInOrigin = "";
mInTarget = "";
senario();
verify();
}
@Test
public void test5() {
mInOrigin = "/";
mInTarget = "/";
senario();
verify();
}
@Test
public void test6() {
mInOrigin = "/";
mInTarget = "/abc";
senario();
verify();
}
@Test
public void test7() {
mInOrigin = "/abc";
mInTarget = "/";
senario();
verify();
}
@Test
public void test8() {
mInOrigin = "/abc";
mInTarget = "/abc/";
senario();
verify();
}
@Test
public void test9() {
mInOrigin = "/abc/";
mInTarget = "/abc";
senario();
verify();
}
@Test
public void test10() {
mInOrigin = "/abc";
mInTarget = "/abc";
senario();
verify();
}
@Test
public void test11() {
mInOrigin = "";
mInTarget = new File(".").getAbsolutePath();
senario();
verify();
}
@Test
public void test12() {
mInOrigin = new File(".").getAbsolutePath();
mInTarget = "";
senario();
verify();
}
// @Test
// public void test() {
// mInOrigin = "";
// mInTarget = "";
// senario();
// verify();
// }
private void senario() {
mExpectedRelativePath = RelativePath0
.relativePath(mInOrigin, mInTarget);
mActualRelativePath = RelativePath.relativePath(mInOrigin, mInTarget);
}
private void verify() {
assertThat(mActualRelativePath, is(equalTo(mExpectedRelativePath)));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.