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.

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.

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;
  }
391a4395921d2dfcdd0c9d3b40edbee1

David

August 31, 2009, August 31, 2009 23:08, permalink

No rating. Login to rate!

i would like to use the second method, but the problem is, i absolutely have no idea what the class 'DataUtil' should be... your own implementation??

would be nice if you could email me, thx!

D41d8cd98f00b204e9800998ecf8427e

Andy Roberts

January 21, 2010, January 21, 2010 15:42, permalink

No rating. Login to rate!

There's some code on StackOverflow which makes this a doddle. See http://stackoverflow.com/questions/1399126/java-util-zip-recreating-directory-structure. The below code will emit the string "path/myfile.txt".

File mydir = new File("C:\\mydir");
File myfile = new File("C:\\mydir\\path\\myfile.txt");
System.out.println(mydir.toURI().relativize(myfile.toURI()).getPath());

Your refactoring





Format Copy from initial code

or Cancel