簡體   English   中英

從Java訪問外部.jar資源

[英]Access external .jar resources from java

我正在開發一個多模塊Java項目,該項目包含相互依賴的Eclipse中的多個項目,現在要添加GUI主題支持,我創建了一個Java項目,該項目不包含任何代碼,僅包含圖標和圖片所需的代碼。 GUI,我將其制作為Java項目,因此Maven會將其構建為.jar。 現在有一個主應用程序,它將多個項目加載到主GUI中,該GUI現在從實際模塊中的資源中獲取其圖標。 我要做的就是從包含在主應用程序.jar的類路徑中的外部虛擬.jar加載所有這些資源。 到目前為止,我發現的每種方法似乎都不起作用。 .jar不包含實際的Java .classes,因此沒有要引用的ClassLoader。 還有其他方法可以在不提取.jar的情況下加載圖片嗎?

您可以嘗試的三件事:

  1. 在資源罐中創建一個虛擬類,您可以使用它來獲取ClassLoader參考。
  2. 如果您知道,則使用URLClassLoader,jar文件將位於其中。
  3. 您始終可以通過擴展java.lang.ClassLoader來創建自己的ClassLoader。

將外部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。

您可以獲取所有資源(classpath上的所有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:file資源,因此...拆分如下所示的字符串:

jar:文件:/Users/rick/.m2/repository/invoke/invoke/1.0-SNAPSHOT/invoke-1.0-SNAPSHOT.jar!/ org / node /

進入這個

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

和這個

/ org / node /

這是執行上述操作的代碼,沒有煩人的錯誤檢查。 :)

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

類路徑資源永遠不能真正以起始斜杠開頭。 從邏輯上講,它們是這樣做的,但實際上,您必須刪除它。 這是類路徑資源的已知行為。 除非資源位於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 :)
                }
            }

您可以在此處看到完整的示例: Pleasanton中的Sleepless

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM