Skip to main content

How to convert java.net.URL to java.io.File?

Posted by kohsuke on April 25, 2007 at 5:07 PM PDT

Often you are in a situation where need to convert a file://... URLs to java.io.File object. Doing this correctly is not trivial (and I still don't know what I'm writing here is the correct way.)

The first code I tried (which I saw somewhere a long time ago) is...

File f = new File(url.getPath());

This actually works for simple cases, like for file:/path/to/abc (which is actually a malformed file URL since it's missing //) or file:///path/to/abc (the correct file URL syntax.) However, this fails to work when the path contains URL-unsafe characters, such as file:///c:/Documents%20and%20Settings/..., because "%20" ends up in file name, which is wrong.

We've been told that java.net.URI is added in JDK1.5 to replace the broken URL class, so why don't we try that?

File f = new File(url.toURI());

This nicely converts %20 to a space (and all the other escaped characters.) The problem solved? Nope. URI is very draconian, and it fails to handle URLs like file:///c:/Documents and Settings/. This URL is broken as far as RFCs are concerned, but the reality is that java.net.URL accepts it happily, so you often end up seeing this. I'm sure many have done new URL("file://"+fileName); — those are the code that creates this URL.

So the current version I have is to combine both:

File f;
try {
  f = new File(url.toURI());
} catch(URISyntaxException e) {
  f = new File(url.getPath());
}

If only we had File(URL) constructor...

Related Topics >>

Comments

Trying to parse obviously malformed URLs is a bad ...

Trying to parse obviously malformed URLs is a bad idea.

URI is indeed better, but does not handle UNC paths on Windows. You need to use: http://docs.oracle.com/javase/7/docs/api/java/nio/file/Paths.html#get(java.net.URI)

Sadly, even using this technique you can get an ...

Sadly, even using this technique you can get an IllegalArgumentException if you're passing in a URL that does not point to a true physical file. For instance, if you use: ClassLoader.getResource("path"), you may end up with a hierarchical URL which points to a resource nested in a JAR. In this case you're better off just returning an InputStream to get the contents (instead of a File pointer). If you *really* need a File, probably best to make a temp one to deleteOnExit and serialize the contents in there.

Mr. Kohsuke, you saved my life. :D Thanks!

Mr. Kohsuke, you saved my life. :D Thanks!