49

I have an absolute path to file A.

I have a relative path to file B from file A's directory. This path may and will use ".." to go up the directory structure in arbitrarily complex ways.

Example A:

  • C:\projects\project1\module7\submodule5\fileA

Example Bs:

  • ..\..\module3\submodule9\subsubmodule32\fileB
  • ..\submodule5\fileB
  • ..\..\module7\..\module4\submodule1\fileB
  • fileB

How do I combine the two in order to get the simplest possible absolute path to file B?

1
  • 1
    tl;dr answer: new File("my/path").getCanonicalPath() Commented Jul 13, 2017 at 12:44

9 Answers 9

53

If I get your problem right, you could do something like this:

File a = new File("/some/abs/path"); File parentFolder = new File(a.getParent()); File b = new File(parentFolder, "../some/relative/path"); String absolute = b.getCanonicalPath(); // may throw IOException 
Sign up to request clarification or add additional context in comments.

2 Comments

But the absolute path can have ..'s in it if I do that. I don't want those. Is there a way to get rid of them from the resulting absolute path?
@Tom: Using getCanonicalPath() instead of getAbsolutePath() is probably what you're looking for, in that case.
30
String absolutePath = FileSystems.getDefault().getPath(mayBeRelativePath).normalize().toAbsolutePath().toString(); 

5 Comments

Can you explain a bit more what you are doing here?
FileSystems.getDefault() gets default file system. For this file system convert a mayBeRelativePath string to a Path object. normalize() it, that is remove constructions like ../abc/../ from any parts of the path. Transform toAbsolutePath() if it is not an absolute yet and get the path as a string.
@rssdev10 Thanks a bunch, this worked great in my testing and is only a single line in comparison to all other answers containing 3-20 lines for the same thing.
Looks great but Java doesn't see FileSystems as an import.
@Andrew FileSystems are available only from Java 7 & above
16

In Java 7 you can also use the Path interface:

Path basePath = FileSystems.getDefault().getPath("C:\\projects\\project1\\module7\\submodule5\\fileA"); Path resolvedPath = basePath.getParent().resolve("..\\..\\module3\\submodule9\\subsubmodule32\\fileB"); // use getParent() if basePath is a file (not a directory) Path abolutePath = resolvedPath.normalize(); 

1 Comment

Good answer, but you need to replace those \ with \\ or it won't compile
5

From your question, if i could get it right, you are looking to get abolute path from relative path, then you can do following.

File b = new File("../some/relative/path"); String absolute = b.getCanonicalPath(); // may throw IOException 

or shorthand notation can be,

String absolute = new File("../some/relative/path").getCanonicalPath(); 

Comments

3

Try FilenameUtils.normalize() from Apache commons-io

1 Comment

why add external dependencies when standard Java NIO does the job?
1

What's better than just creating a utility that converts relative paths to absolute paths is to create a utility that converts any path passed to it into an absolute path so that you don't have to check on the client-side.

The below code works for me in both cases and I've used the String type at the signature of the method (both parameter and return value):

public static String toAbsolutePath(String maybeRelative) { Path path = Paths.get(maybeRelative); Path effectivePath = path; if (!path.isAbsolute()) { Path base = Paths.get(""); effectivePath = base.resolve(path).toAbsolutePath(); } return effectivePath.normalize().toString(); } 

Changing the above code to expose Path types on the signature of the method is trivial (and actually easier) but I think that using String on the signature gives more flexibility.

2 Comments

What’s the difference to just calling path.toAbsolutePath().normalize()?
@QuirinF.Schroll sorry, no longer working with Java...
0

Here is the sample code that works for me.

 public String absolutePath(String relative, String absoluteTo) { String[] absoluteDirectories = relative.split("\\\\"); String[] relativeDirectories = absoluteTo.split("\\\\"); int relativeLength = relativeDirectories.length; int absoluteLength = absoluteDirectories.length; int lastCommonRoot = 0; int index; for (index = 0; index < relativeLength; index++) if (relativeDirectories[index].equals("..\\\\")) lastCommonRoot = index; else break; StringBuilder absolutePath = new StringBuilder(); for (index = 0; index < absoluteLength - lastCommonRoot; index++) { if (absoluteDirectories[index].length() > 0) absolutePath.append(absoluteDirectories[index] + "\\\\"); } for (index = lastCommonRoot; index < relativeLength - lastCommonRoot; index++) { if (relativeDirectories[index].length() > 0) absolutePath.append(relativeDirectories[index] + "\\\\"); } return absolutePath.toString(); } 

Also I the conversion to relative:

public String relativePath(String absolute, String relativeTo) throws Exception { String[] absoluteDirectories = absolute.split("\\\\"); String[] relativeDirectories = relativeTo.split("\\\\"); int length = absoluteDirectories.length < relativeDirectories.length ? absoluteDirectories.length : relativeDirectories.length; int lastCommonRoot = -1; int index; for (index = 0; index < length; index++) if (absoluteDirectories[index].equals(relativeDirectories[index])) lastCommonRoot = index; else break; if (lastCommonRoot > -1){ StringBuilder relativePath = new StringBuilder(); for (index = lastCommonRoot + 1; index <absoluteDirectories.length; index++) if (absoluteDirectories[index].length() > 0) relativePath.append("..\\\\"); for (index = lastCommonRoot + 1; index <relativeDirectories.length-1; index++) relativePath.append(relativeDirectories[index] + "\\\\"); relativePath.append(relativeDirectories[relativeDirectories.length - 1]); return relativePath.toString(); } else{ throw new Exception("No common root found between working direcotry and filename"); } } 

Comments

0

I know it isn't the best solution but can't you just combine the substring of fileA's path from 0 to the lastIndexOf("\") with fileB's path.

Example A:

  • C:\projects\project1\module7\submodule5\fileA

Example Bs:

  • ..\..\module3\submodule9\subsubmodule32\fileB

C:\projects\project1\module7\submodule5\..\..\module3\submodule9\subsubmodule32\fileB

If you don't want the .. in there then, it would take longer, but I recommend going through the path for fileB and keep taking the substring from 0 to the first index of \. Then check the substring. If it is .. then remove the substring from there and remove the substring from fileA's path from lastIndexOf(\) to length. Then repeat. That way you are removing the folders you don't need and the ..s.

So :

Example A:

  • C:\projects\project1\module7\submodule5\fileA

Example Bs:

  • ..\..\module3\submodule9\subsubmodule32\fileB

    --> C:\projects\project1\module3\submodule9\subsubmodule32\fileB

Comments

-3

Windows path to full Java path.

String winPath = downloadPath+"\\"+dir_contents[i].getName(); String absPath = winPath.replace("\\","\\\\"); 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.