A9c8a6d8eed437bb33d504cae365bf57

I call:
File f = new File("c:\\windows\\system32\\asd.tmp");
File r = new File("c:\\windows\\web");

getRelativePath(f,r) returns "..\\system32\\asd.tmp");

The author of this method put two ugly lines for solving a windows problem.
I tried this code and I think it works fine, but I'm not sure this is the best way to do it.

A function that finds the relative path of a file is often useful.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
	public static String getRelativePath(File file, File relativeTo) throws IOException {
		/*
		 * windows seems in some cases not to stop getParent() at 'c:\', which I
		 * considered to be root. For that reason I had to tweak in the
		 * following to 'ugly' lines:
		 */
		file = new File(file + File.separator + "89243jmsjigs45u9w43545lkhj7").getParentFile();
		relativeTo = new File(relativeTo + File.separator + "984mvcxbsfgqoykj30487df556").getParentFile();

		File origFile = file;
		File origRelativeTo = relativeTo;
		ArrayList<File> filePathStack = new ArrayList<File>();
		ArrayList<File> relativeToPathStack = new ArrayList<File>();
		// build the path stack info to compare it afterwards
		file = file.getCanonicalFile();
		while (file != null) {
			filePathStack.add(0, file);
			file = file.getParentFile();
		}
		relativeTo = relativeTo.getCanonicalFile();
		while (relativeTo != null) {
			relativeToPathStack.add(0, relativeTo);
			relativeTo = relativeTo.getParentFile();
		}
		// compare as long it goes
		int count = 0;
		file = filePathStack.get(count);
		relativeTo = relativeToPathStack.get(count);
		while ((count < filePathStack.size() - 1) && (count < relativeToPathStack.size() - 1) && file.equals(relativeTo)) {
			count++;
			file = filePathStack.get(count);
			relativeTo = relativeToPathStack.get(count);
		}
		if (file.equals(relativeTo))
			count++;
		// up as far as necessary
		StringBuffer relString = new StringBuffer();
		for (int i = count; i < relativeToPathStack.size(); i++) {
			relString.append(".." + File.separator);
		}
		// now back down to the file
		for (int i = count; i < filePathStack.size() - 1; i++) {
			relString.append(filePathStack.get(i).getName() + File.separator);
		}
		relString.append(filePathStack.get(filePathStack.size() - 1).getName());
		// just to test
		File relFile = new File(origRelativeTo.getAbsolutePath() + File.separator + relString.toString());
		if (!relFile.getCanonicalFile().equals(origFile.getCanonicalFile())) {
			throw new IOException("Failed to find relative path.");
		}
		return relString.toString();
	}

Refactorings

No refactoring yet !

Ee573f2fb953ffeb544fca3e4d12ffad

Mustafa

November 3, 2008, November 03, 2008 07:45, permalink

No rating. Login to rate!

I cannot say that this is a better solution, but just another way with string manipulation.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
  public static String getRelativePath(File file, File relativeTo)
  {
    String path = "";
    
    List<String> fileList = DataUtil.getDelimitedStringAsList(file.getAbsolutePath(),File.separator);
    List<String> relativeList = DataUtil.getDelimitedStringAsList(relativeTo.getAbsolutePath(),File.separator);
    
    int size = fileList.size();
    int relativeSize = relativeList.size();
    int count = 0;
    
    //ignore same parents
    while(count<size && count<relativeSize)
    {
      if(fileList.get(count).equals(relativeList.get(count)))
        count++;
      else
        break;
    }
    
    for (int i = count; i < relativeSize; i++) 
    {
      path += ".." + File.separator;
    }
    
    for (int i = count; i < size; i++) 
    {
      path += fileList.get(i) + File.separator;
    }
    
    if(path.indexOf(File.separator)>-1)
      path = path.substring(0,path.lastIndexOf(File.separator));
    
    return path;    
  }
  
  public static List getDelimitedStringAsList(String str, String delimiter)
  {
    List resultList = new ArrayList();
    StringTokenizer st = new StringTokenizer(str, delimiter);
    while (st.hasMoreTokens())
      resultList.add(st.nextToken());
    return resultList;
  }

Your refactoring





Format Copy from initial code

or Cancel