8 Replies Latest reply: Jan 6, 2005 9:19 AM by 807596 RSS

    again: getting a relative path of a file

    807596
      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
          No obvious way I know of... I'd go for String parsing.

          ***Annie***
          • 2. Re: again: getting a relative path of a file
            dcminter
            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
              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
                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
                  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
                    "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
                      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
                        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();
                        }