Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java's File.toString or Path.toString with a specific path separator

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.

like image 975
Malte Schwerhoff Avatar asked Jul 15 '12 17:07

Malte Schwerhoff


People also ask

What is file path separator?

The path separator is a character commonly used by the operating system to separate individual paths in a list of paths.

What is path separator in Java?

pathSeparator: Platform dependent variable for path-separator. For example PATH or CLASSPATH variable list of paths separated by ':' in Unix systems and ';' in Windows system. File. pathSeparatorChar: Same as pathSeparator but it's char.

How do I use a file separator?

A file separator is a character that is used to separate directory names that make up a path to a particular location. This character is operating system specific. On Microsoft Windows, it is a back-slash character (), e.g. C:myprojectmyfilesome. properties.

Which of the following is a filename path separator in Linux?

If you prefer to hard-code the directory separator character, you should use the forward slash ( / ) character. It is the only recognized directory separator character on Unix systems, as the output from the example shows, and is the AltDirectorySeparatorChar on Windows.


2 Answers

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.

like image 139
IRQ Avatar answered Nov 15 '22 18:11

IRQ


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?)

like image 33
Jason S Avatar answered Nov 15 '22 19:11

Jason S