繁体   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