Converting Relative Paths to Absolute Paths

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?

Answers


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

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();

String absolutePath = FileSystems.getDefault().getPath(mayBeRelativePath).normalize().toAbsolutePath().toString();


Try FilenameUtils.normalize() from Apache commons-io


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();

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.


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");
        }            
    }

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


Windows path to full Java path.

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

Need Your Help

Adding items to wxpython combobox...?

python database combobox wxpython

I am new to python programming and to this forum as well. I am preparing a wxpython program (GUI) which has 2 comboboxes. First is for the Teams and the second for team members. All the data is sto...

*.dmp file import in Oracle

oracle import schema

I need to import data from *.dmp file say mydump.dmp.