Question

I am developing a Scala application on Windows, and I need to insert a path to a file into an HTML template. I use Java's io and nio to work with files and paths.

/* The paths actually come from the environment. */
val includesPath = Paths.get("foo\\inc")
val destinationPath = Paths.get("bar\\dest")

/* relativeIncludesPath.toString == "..\\foo\\inc", as expected */
val relativeIncludesPath = destinationPath.relativize(includesPath)

The problem is that the output of relativeIncludesPath.toString contains backslashes \ as separators - because the application runs on Windows - but since the path is to be inserted into a HTML template, it must contain forward slashes / instead.

Since I couldn't find anything like file/path.toStringUsingSeparator('/') in the docs, I am currently helping myself with relativeIncludesPath.toString.replace('\\', '/'), which I find rather unappealing.

Question: Is there really no better way than using replace?

I also experimented with Java's URI, but it's relativize is incomplete.

Was it helpful?

Solution

The Windows implementation of the Path interface stores the path internally as a string (at least in the OpenJDK implementation) and simply returns that representation when toString() is called. This means that no computation is involved and there is no chance to "configure" any path separator.

For this reason, I conclude that your solution is the currently the best option to solve your problem.

OTHER TIPS

I just ran into this issue. If you have a relative path, you can use the fact that Path is an Iterable<Path> of its elements, following an optional initial root element, and then can concatenate the pieces yourself with forward slashes. Unfortunately the root element can contain slashes, e.g. in Windows you get root elements like c:\ and \\foo\bar\ (for UNC paths), so it seems like no matter what you still have to replace with forward slashes. But you could do something like this...

static public String pathToPortableString(Path p)
{
    StringBuilder sb = new StringBuilder();
    boolean first = true;
    Path root = p.getRoot();
    if (root != null)
    {
        sb.append(root.toString().replace('\\','/'));
        /* root elements appear to contain their
         * own ending separator, so we don't set "first" to false
         */            
    }
    for (Path element : p)
    {
       if (first)
          first = false;
       else
          sb.append("/");
       sb.append(element.toString());
    }
    return sb.toString();        
}

and when I test it with this code:

static public void doit(String rawpath)
{
    File f = new File(rawpath);
    Path p = f.toPath();
    System.out.println("Path: "+p.toString());
    System.out.println("      "+pathToPortableString(p));
}

static public void main(String[] args) {
    doit("\\\\quux\\foo\\bar\\baz.pdf");
    doit("c:\\foo\\bar\\baz.pdf");
    doit("\\foo\\bar\\baz.pdf");
    doit("foo\\bar\\baz.pdf");
    doit("bar\\baz.pdf");
    doit("bar\\");
    doit("bar");
}

I get this:

Path: \\quux\foo\bar\baz.pdf
      //quux/foo/bar/baz.pdf
Path: c:\foo\bar\baz.pdf
      c:/foo/bar/baz.pdf
Path: \foo\bar\baz.pdf
      /foo/bar/baz.pdf
Path: foo\bar\baz.pdf
      foo/bar/baz.pdf
Path: bar\baz.pdf
      bar/baz.pdf
Path: bar
      bar
Path: bar
      bar

The textual substitution of backslash with forward slash is definitely easier, but I have no idea whether it would break some devious edge case. (Can there be backslashes in Unix paths?)

You can fetch most of the system properties in Java. Take a look at this link:

http://docs.oracle.com/javase/tutorial/essential/environment/sysprop.html

You want this:

Key: "file.separator"
Meaning: Character that separates components of a file path. This is "/" on UNIX and "\" on Windows.

String sep = System.getProperty("path.separator");
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top