2012-04-16 172 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