2012-04-16 139 views
1

我正在开发一个多模块Java项目,它由多个互相依赖的Eclipse项目组成,现在添加GUI主题支持我创建了一个不包含任何Java项目代码,只是图形用户界面所需的图标和图片,我把它做成了一个Java项目,所以Maven会将它构建成一个.jar。现在有一个主要的应用程序将多个项目加载到主GUI中,该主GUI从当前实际模块中的资源获取其图标。我想要做的就是从主应用程序的.jar的类路径中包含的外部虚拟.jar文件中加载所有这些资源。目前为止我发现的每种方法似乎都不起作用。 .jar不包含实际的java .class,所以没有ClassLoader可供引用。有没有其他方法可以在不提取.jar的情况下加载图片?从java访问外部.jar资源

+0

这个问题看起来像http://stackoverflow.com/questions/403256/how-do-i-read-a-resource-file-from-a-java-jar-file – Kappei 2012-04-16 14:58:38

+1

的副本*“他说。罐子不包含任何实际的Java .classes,所以没有ClassLoader的引用。“*如果罐是应用程序的运行时类路径中,资源应该使用的getResource()(在上下文类加载器中找到)用“从根路径”,如'/路径/到/ the.png' – 2012-04-16 14:59:36

+0

它实际上是在我的部分简单的错误(I使用一个不存在的路径)。显然,Java有从classpath中抢夺资源,无论身在何处的getResource()是由所谓的没有问题。有人向我解释说,Java在运行时基本上用所有使用过的jar构建了一个文件系统,因此访问非常简单并且可以在全球范围内使用。感谢大家的建议! – user1307791 2012-04-20 18:06:56

回答

0

三样东西,你可以尝试:

  1. 创建资源罐子,你可以用它来获取类加载器的参考虚拟类。
  2. 使用URLClassLoader,如果您知道,您的jar文件驻留在哪里。
  3. 您始终可以通过扩展java.lang.ClassLoader来创建自己的ClassLoader。
0

对待外部JAR文件作为一个zip压缩文件并读取图像/资源是这样的:

public ZipStuff(String filename) throws IOException 
{ 
    ZipFile zf = new ZipFile(filename); 
    Enumeration<? extends ZipEntry> entries = zf.entries(); 

    while (entries.hasMoreElements()) { 
     ZipEntry ze = entries.nextElement(); 
     ImageIcon ii = new ImageIcon(ImageIO.read(zf.getInputStream(ze))); 
     JLabel l = new JLabel(ii); 
     getContentPane().add(l); 
    } 
    setVisible(true); 
    pack(); 
} 

在这种情况下,我有一个单一的图像的jar文件,我加载到一个JLabel的。 ZipStuff类是一个JFrame。

0

你可以得到所有的资源(类路径上所有jar文件应该工作,即使一个没有班):

Enumeration<URL> resources = null; 
    try { 
     resources = Thread.currentThread().getContextClassLoader().getResources(someResource); 
    } catch (Exception ex) { 
     //no op  
    } 
    if (resources == null || !resources.hasMoreElements()) { 
     resources = ClasspathReader.class.getClassLoader().getResources(someResource); 
    } 

然后检查,看看目前的资源是文件。您可以将文件直接作为文件处理。 但你的问题是关于jar文件,所以我不会去那里。

while (resources.hasMoreElements()) { 
     URL resource = resources.nextElement(); 


     if (resource.getProtocol().equals("file")) { 
      //if it is a file then we can handle it the normal way. 
      handleFile(resource, namespace); 
      continue; 
     } 

此时你应该只罐子:文件资源,使... 分手了,看起来像这样的字符串:

的jar:文件:/Users/rick/.m2/repository/调用/调用/ 1.0-SNAPSHOT /调用-1.0-SNAPSHOT.jar!/组织/节点/

这个

/Users/rick/.m2/repository/invoke/invoke/1.0-SNAPSHOT/invoke -1.0-SNAPSHOT.jar

/组织/节点/

下面是代码做讨厌的错误检查的上述不含。:)

 String[] split = resource.toString().split(":"); 
     String[] split2 = split[2].split("!"); 
     String zipFileName = split2[0]; 
     String sresource = split2[1]; 

     System.out.printf("After split zip file name = %s," + 
       " \nresource in zip %s \n", zipFileName, sresource); 

现在我们有zip文件名,所以我们可以阅读:

 ZipFile zipFile = new ZipFile(zipFileName); 

现在,我们可以通过它的条目迭代:

 Enumeration<? extends ZipEntry> entries = zipFile.entries(); 

     while (entries.hasMoreElements()) { 
      ZipEntry entry = entries.nextElement(); 

      /* If it is a directory, then skip it. */ 
      if (entry.isDirectory()) { 
       continue; 
      } 

      String entryName = entry.getName(); 
      System.out.printf("zip entry name %s \n", entryName); 

看它是否与启动我们正在寻找的资源。

  if (!entryName.startsWith(someResource)) { 
       continue; 
      } 

有两个技巧我先前做的,看它是否是一个目录

boolean isDir = !someResource.endsWith(".txt"); 

这只能是因为我在寻找与.TXT结尾的资源,我以为,如果它不结束用.txt表示它是dir/foo/dir和/ foo/dir /都可以。

另一个诀窍是这样的:

if (someResource.startsWith("/")) { 
     someResource = someResource.substring(1); 
    } 

Classpath的资源永远不能用一个开始斜线开始。从逻辑上讲他们是这样做的,但实际上你必须去掉它。这是类路径资源的已知行为。除非资源位于jar文件中,否则它使用斜杠。底线,通过剥离,它始终有效。

我们需要获得织物的实际文件名。来自条目名称的fileName部分。 其中/foo/bar/foo/bee/bar.txt,我们希望'bar.txt'是fileName。回到我们的while循环中。

 while (entries.hasMoreElements()) { 
      ZipEntry entry = entries.nextElement(); 
      ... 
      String entryName = entry.getName(); //entry is zipEntry 
      String fileName = entryName.substring(entryName.lastIndexOf("/") + 1); 


      /** See if the file starts with our namespace and ends with our extension. */ 
      if (fileName.startsWith(namespace) && fileName.endsWith(".txt")) { 

接下来我们看看这些进入我们的标准相匹配,如果是读取文件到System.out的内容。

  try (Reader reader = new InputStreamReader(zipFile.getInputStream(entry))) { 
        StringBuilder builder = new StringBuilder(); 
        int ch = 0; 
        while ((ch = reader.read()) != -1) { 
         builder.append((char) ch); 

        } 
        System.out.printf("zip fileName = %s\n\n####\n contents of file %s\n###\n", 
        entryName, builder); 
       } catch (Exception ex) { 
        ex.printStackTrace();//it is an example/proto :) 
       } 
      } 

你可以在这里看到完整的例子:Sleepless in Pleasanton