This discussion is archived
8 Replies Latest reply: Jan 6, 2005 7:19 AM by 807596 RSS

again: getting a relative path of a file

807596 Newbie
Currently Being Moderated
Hi folks,

Say I have a file: new File("c:/root/documents/file.txt")
and a path: new File("c:/root/bin")
and I want to find the relative path of the file to the later path.
So the expected outcome in this example should be:
"../documents/file.txt"

Is there any way to achieve this other then string parsing
the paths, which i obviously don't want to do.

Thx
  • 1. Re: again: getting a relative path of a file
    807596 Newbie
    Currently Being Moderated
    No obvious way I know of... I'd go for String parsing.

    ***Annie***
  • 2. Re: again: getting a relative path of a file
    dcminter Newbie
    Currently Being Moderated
    I don't think so. But...

    You may find that using the File.getCanonicalPath method abates some of your concerns about using string manipulation to get at this information.

    Dave.
  • 3. Re: again: getting a relative path of a file
    807596 Newbie
    Currently Being Moderated
    Thanks for your help.

    I coded it as follows:
    (you know the rules, no guarantee at all that this code works, etc.. etc..)


    public static String getRelativePath(File file, File relativeTo) throws IOException {
    File origFile = file;
    File origRelativeTo = relativeTo;
    ArrayList filePathStack = new ArrayList();
    ArrayList relativeToPathStack = new ArrayList();
    // 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 = (File)filePathStack.get(count);
    relativeTo = (File)relativeToPathStack.get(count);
    while (file.equals(relativeTo)) {
    count++;
    file = (File)filePathStack.get(count);
    relativeTo = (File)relativeToPathStack.get(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(((File)filePathStack.get(i)).getName()+File.separator);
    }
    relString.append(((File)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();
    }
  • 4. Re: again: getting a relative path of a file
    796254 Newbie
    Currently Being Moderated
    I think absolute file paths like this usually run into trouble. They're a bad way to go, IMO.

    I find that getResourceAsStream() is a better way to go. Now you look for files in the CLASSPATH of your app. It makes your app more portable AND keeps the files close to your app where other maintainence programmers can actually find them.

    If it's a desktop app, call java.lang.ClassLoader.getResourceAsStream(). If it's a Web app, use javax.servlet.ServletContext.getResourceAsStream().

    %
  • 5. Re: again: getting a relative path of a file
    807596 Newbie
    Currently Being Moderated
    I understand your point.

    However in my app the user is allowed to access any files
    from the filesystem and 'link' them to the application.

    Later the application (and it's surrounding folders) will be
    deployed to another place and links created by the user
    should keep working
  • 6. Re: again: getting a relative path of a file
    dcminter Newbie
    Currently Being Moderated
    "Later the application (and it's surrounding folders) will be
    deployed to another place"

    Then I would recommend declaring a specific folder as being the "base" folder. E.g.
    String base = "C:/development/";
    Subsequent filepaths are determined relative to this:
    String customPath = "my/custom/folder/readme.txt";
    String fullPath = base + customPath;
    By retaining the information in your application, you can then easily change the working folder on the target system to:
    String base = "C:/program files/deployment/";
    And reconstruct paths appropriately.

    Dave.
  • 7. Re: again: getting a relative path of a file
    807596 Newbie
    Currently Being Moderated
    Dave,

    Thanks for you answer. Basically i am doing what you suggest already.

    The question, however is, how do find from any arbitrary absolute
    path c:\development\xyz\file.txt an relative path to my base folder
    c:\development ?
  • 8. Re: again: getting a relative path of a file
    807596 Newbie
    Currently Being Moderated
    The previous version of my solution had to bugs, let'me update here:
    - First 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();
    - Second there was bug in the condition of a while loop

    Thanks all, for your answers. I consider this thread solved for my part.



    Now the hopefully finally version is here:



    public static String getRelativePath(File file, File relativeTo) throws IOException {
    file = new File(file+File.separator+"89243jmsjigs45u9w43545lkhj7").getParentFile();
    relativeTo = new File(relativeTo+File.separator+"984mvcxbsfgqoykj30487df556").getParentFile();
    File origFile = file;
    File origRelativeTo = relativeTo;
    ArrayList filePathStack = new ArrayList();
    ArrayList relativeToPathStack = new ArrayList();
    // 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 = (File)filePathStack.get(count);
    relativeTo = (File)relativeToPathStack.get(count);
    while ((count<filePathStack.size()-1) && (count<relativeToPathStack.size()-1) && file.equals(relativeTo)) {
    count++;
    file = (File)filePathStack.get(count);
    relativeTo = (File)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(((File)filePathStack.get(i)).getName()+File.separator);
    }
    relString.append(((File)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();
    }