20

I get a jar file url at runtime as:

jar:file:///C:/proj/parser/jar/parser.jar!/test.xml

How can this be converted to a valid path as:

C:/proj/parser/jar/parser.jar.

I have already tried using File(URI), getPath(), getFile() in vain.

Lucifer
  • 29,392
  • 25
  • 90
  • 143

7 Answers7

41

This might do it, if MS-Windows is not offended by a leading slash:

    final URL jarUrl =
        new URL("jar:file:/C:/proj/parser/jar/parser.jar!/test.xml");
    final JarURLConnection connection =
        (JarURLConnection) jarUrl.openConnection();
    final URL url = connection.getJarFileURL();

    System.out.println(url.getFile());
starblue
  • 55,348
  • 14
  • 97
  • 151
  • I am going with exactly this solution, although I wish there was a way to do this without opening the jar (or parsing directly, of course); seems like URL needs to understand this weird ! syntax, or else a subclass needs to exist which understands it. – skiphoppy Jul 15 '09 at 17:23
  • 6
    (In Java7) JarURLConnection doesn't open the JAR file when you execute the above code. It just parses the URL on your behalf. – Gili Nov 04 '11 at 18:36
  • @Marcono1234 This will throw an exception if the URI points to something inside a jar, thus having exclamation marks , as is the case for OP. – Dmitry Avtonomov May 14 '19 at 16:29
  • @DmitryAvtonomov, you are right, my suggestion to use `Paths.get` will not work. I removed that comment. – Marcono1234 May 18 '19 at 10:31
3

Not sure of any exact method that will give you what you want, but this should get you close:

import static org.junit.Assert.assertEquals;

import java.net.URL;

import org.junit.Test;

public class UrlTest {

    @Test
    public void testUrl() throws Exception {
        URL jarUrl = new URL("jar:file:/C:/proj/parser/jar/parser.jar!/test.xml");
        assertEquals("jar", jarUrl.getProtocol());
        assertEquals("file:/C:/proj/parser/jar/parser.jar!/test.xml", jarUrl.getFile());
        URL fileUrl = new URL(jarUrl.getFile());
        assertEquals("file", fileUrl.getProtocol());
        assertEquals("/C:/proj/parser/jar/parser.jar!/test.xml", fileUrl.getFile());
        String[] parts = fileUrl.getFile().split("!");
        assertEquals("/C:/proj/parser/jar/parser.jar", parts[0]);
    }
}

Hope this helps.

toolkit
  • 49,809
  • 17
  • 109
  • 135
  • Very close, but the usage of split() is too much low-level parsing for me. Sun's URL implementation doesn't seem to provide methods to deal with this weird jarfile.jar!path/to/specific/file syntax for Sun's weird jar URLs; the whole shebang (pun intended) is returned by getPath(). But JarURLConnection, as starblue mentioned, seems to work, although only through opening up the jar. – skiphoppy Jul 15 '09 at 17:22
1

Some might consider this to be a bit 'hacky', but it'll do the job in that instance and i'm sure it'd perform a damn sight better than creating all those objects in the other suggestions.

String jarUrl = "jar:file:/C:/proj/parser/jar/parser.jar!/test.xml";

jarUrl = jarUrl.substring(jarUrl.indexOf('/')+1, jarUrl.indexOf('!'));
James Camfield
  • 1,636
  • 3
  • 16
  • 24
  • This will fail miserably if there are any special (percent encoded) characters in the URL. – cbley Jun 21 '16 at 09:34
1

This solution will handle spaces in the path.

String url = "jar:file:/C:/dir%20with%20spaces/myjar.jar!/resource";
String fileUrl = url.substring(4, url.indexOf('!'));
File file = new File(new URL(fileUrl).toURI());
String fileSystemPath = file.getPath();

or with a URL object to begin with:

...
String fileUrl = url.getPath().substring(0, url.indexOf('!'));
...
dcstraw
  • 3,243
  • 3
  • 29
  • 38
1

I just had to do this.

        URL url = clazz.getResource(clazz.getSimpleName() + ".class");
        String proto = url.getProtocol();
        boolean isJar = proto.equals("jar"); // see if it's in a jar file URL

        if(isJar)
        {
            url = new URL(url.getPath()); // this nicely strips off the leading jar: 
            proto = url.getProtocol();
        }

        if(proto.equals("file"))
        {
             if(isJar) 
                // you can truncate it at the last '!' here
        } 
        else if(proto == "http") {
            ...
peterk
  • 5,136
  • 6
  • 33
  • 47
0
  //This code will work on both Windows and Linux
  public String path()
  {
  URL url1 = getClass().getResource("");
  String urs=url1.toString();
  urs=urs.substring(9);
  String truepath[]=urs.split("parser.jar!");
  truepath[0]=truepath[0]+"parser.jar";
  truepath[0]=truepath[0].replaceAll("%20"," ");
  return truepath[0];
  }
-1

You can do this.This works

    ClassLoader loader = this.getClass().getClassLoader();
    URL url = loader.getResource("resource name");
    String[] filePath = null;
    String protocol = url.getProtocol();
    if(protocol.equals("jar")){
        url = new URL(url.getPath());
        protocol = url.getProtocol();
    }
    if(protocol.equals("file")){
        String[] pathArray = url.getPath().split("!");
        filePath = pathArray[0].split("/",2);
    }
    return filePath[1];