如何从包含"!"和jar文件中特定文件的jar:URL中获取仅jar URL?

20

我在运行时得到一个Jar文件的URL:

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

如何将此转换为有效路径:

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

我已经试过使用File(URI)getPath()getFile(),但都没有成功。

7个回答

42

如果MS-Windows不介意前导斜杠,这可能会起作用:

    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());

我会采用这个解决方案,虽然我希望有一种方法可以在不打开jar文件(或直接解析)的情况下完成这个操作;似乎URL需要理解这个奇怪的!语法,否则就需要存在一个子类来理解它。 - skiphoppy
6
在Java7中,当您执行以上代码时,JarURLConnection不会打开JAR文件,它只是代表您解析URL。 - Gili
@Marcono1234 如果URI指向JAR内部的内容(例如OP的情况,有感叹号),则会抛出异常。 - Dmitry Avtonomov
@DmitryAvtonomov,你是对的,我建议使用Paths.get不起作用。我已经删除了那个评论。 - Marcono1234

3

我不能确定有哪种确切的方法可以满足您的要求,但是这个方法应该能让您接近目标:

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]);
    }
}

希望这能帮到您。

非常接近,但是split()的使用对我来说太低级了。Sun的URL实现似乎没有提供处理Sun奇怪的jarfile.jar!path/to/specific/file语法的方法;整个shebang(双关语)都由getPath()返回。但是,正如starblue所提到的,JarURLConnection似乎可以工作,尽管只能通过打开jar文件来实现。 - skiphoppy

1

我只是不得不这样做。

        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") {
            ...

1

这个解决方案将处理路径中的空格。

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();

或者可以先使用一个URL对象:

...
String fileUrl = url.getPath().substring(0, url.indexOf('!'));
...

1

有些人可能认为这有点“hacky”,但在那种情况下它会完成任务,我相信它的表现比其他建议中创建所有这些对象要好得多。

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

jarUrl = jarUrl.substring(jarUrl.indexOf('/')+1, jarUrl.indexOf('!'));

如果URL中有任何特殊字符(百分号编码),这将彻底失败。 - cbley

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

你可以这样做。这个有效。

    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];

无法工作:!后面的字符串部分仍未被删除。 - tribbloid

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接