7

I have a File

/user/guest/work/test/src/main/java/Test.java

And a File-Object:

File f = new File("/user/guest/work/test/src/main/java/Test.java");

I need this outputs

System.out.println(f);                   ->                       src/main/java/Test.java
System.out.println(f.getAbsolutePath()); -> /user/guest/work/test/src/main/java/Test.java

I tried:

File relativeTo = new File("/user/guest/work/test");
new File(relativeTo.toURI().relativize(f.toURI()));

but it is throwing a

java.lang.IllegalArgumentException: URI is not absolute
   at java.io.File.<init>(File.java:416)
   at Test.<init>(Test.java:43)

How to get the required output?

Grim
  • 1,938
  • 10
  • 56
  • 123
  • I don't understand why you need `relativize` – OneCricketeer Mar 04 '17 at 03:33
  • I need the relative name to hide the username/project-folder in logging – Grim Mar 04 '17 at 03:34
  • The File constructor needs an absolute path. You can print the relativize value, but not construct a new file from it – OneCricketeer Mar 04 '17 at 03:40
  • Try `File relativeTo = new File("./user/guest/workspace/test");` – Murillo Goulart Mar 04 '17 at 03:41
  • @cricket_007 Hm, only the File-constructor(URI uri) requires a absolute, we have constructors in File that allowes to use relative and absolute, even only relative parameters. – Grim Mar 04 '17 at 03:43
  • @MurilloGoulart Your suggestion creates a File pointing to `/user/tomcat/user/guest/workspace/test` what does not exists and is wrong from my point of view. – Grim Mar 04 '17 at 03:47
  • @Cricket_007 That is simply untrue. Consider `new File("x.tmp")`. – user207421 Jun 26 '17 at 09:36
  • @EJP that's a different constructor than the one that's used in the question, so out of context, sure you are correct – OneCricketeer Jun 26 '17 at 11:30
  • @EJP just for editorial: the term "simply untrue" is only a little bit correct, the truth is never simple so a "untrue" is a little bit more correct. In example `file:///var/log/debug.log` might look like a absolute uri and it will be interpreted to the more qualified `file://localhost/var/log/debug.log` but only if localhost is pointing to `127.0.0.1` then the much more absolute uri is like `file://127.0.0.1/var/log/debug.log`. According to https://tools.ietf.org/html/rfc8089 the real local-absolute uri would be: `file:/var/log/debug.log`. – Grim Jun 26 '17 at 12:20
  • @cricket_007 It is not 'a different constructor than the *one* that's used in the question' [emphasis added]. There are *two* used in the question. Does your comment refer to`File(URI)`? You need to make yourself clear. – user207421 Jun 28 '17 at 04:27
  • @PeterRader Just for editorial, the truth is often extremely simple, and 'a 'little bit more correct' is a pleonasm. – user207421 Jun 28 '17 at 04:28
  • @EJP I am unable to edit my months old comment that perhaps would say "that File constructor". Anyways, I feel like I've made myself clear in the answer below – OneCricketeer Jun 28 '17 at 05:51

2 Answers2

6

relativize returns a URI.

a new File(URI uri) takes...

uri - An absolute, hierarchical URI

You can instead try using the String constructor.

new File(relativeTo.toURI().relativize(f.toURI()).toString());

You have access to that file other ways, however

For example, you can try going through the java.nio.file.Path API instead of java.io.File

Like

Path path = Paths.get("/", "user", "guest", "workspace", 
    "test", "src", "main", "java", "Test.java");
Path other = ...
Path relPath = other.relativize(path);

//    relPath.toString(); // print it
//    relPath.toFile();   // get a file
OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
4

You can use path resolve to relativize file paths

  File f = new File("/user/guest/workspace/test/src/main/java/Test.java");
  File relativeTo = new File("/user/guest/workspace/test");
  System.out.println(new File(relativeTo.toPath().resolve(f.toPath()).toUri()));
Pulkit
  • 3,953
  • 6
  • 31
  • 55