简体   繁体   English

在 a.jar 中获取目录

[英]Getting a directory inside a .jar

I am trying to access a directory inside my jar file.我正在尝试访问 jar 文件中的目录。 I want to go through every of the files inside the directory itself.我想通过目录本身内的每个文件 go 。 I tried, for example, using the following:例如,我尝试使用以下内容:

URL imagesDirectoryURL=getClass().getClassLoader().getResource("Images");

if(imagesFolderURL!=null)
{
    File imagesDirectory= new File(imagesDirectoryURL.getFile());
}

If I test this applet, it works well.如果我测试这个小程序,它运行良好。 But once I put the contents into the jar, it doesn't because of several reasons.但是一旦我将内容放入jar,由于几个原因,它不会。 If I use this code, the URL always points outside the jar, so I have to put the Images directory there.如果我使用这段代码,URL 总是指向 jar 之外,所以我必须把Images目录放在那里。 But if I use new File(imagesDirectoryURL.toURI());但是如果我使用new File(imagesDirectoryURL.toURI()); , it doesn't work inside the jar because I get the error URI not hierarchical . ,它在 jar 内不起作用,因为我得到错误URI not hierarchical I am sure the directory exists inside the jar.我确信该目录存在于 jar 中。 How am I supposed the get the contents of Images inside the jar?我应该如何获取 jar 中的Images内容?

Paths within Jars are paths, not actual directories as you can use them on a file system. Jars 中的路径是路径,而不是实际目录,因为您可以在文件系统上使用它们。 To get all resources within a particular path of a Jar file:要获取 Jar 文件的特定路径中的所有资源:

  • Gain an URL pointing to the Jar.获得指向 Jar 的URL
  • Get an InputStream from the URL .URL获取InputStream
  • Construct a ZipInputStream from the InputStream .InputStream构造一个ZipInputStream
  • Iterate each ZipEntry , looking for matches to the desired path.迭代每个ZipEntry ,寻找与所需路径的匹配项。

..will I still be able to test my Applet when it's not inside that jar? ..当 Applet 不在 jar 内时,我还能测试它吗? Or will I have to program two ways to get my Images?还是我必须编写两种方法来获取我的图像?

The ZipInputStream will not work with loose resources in directories on the file system. ZipInputStream不适用于文件系统目录中的松散资源。 But then, I would strongly recommend using a build tool such as Ant to build (compile/jar/sign etc.) the applet.但是,我强烈建议使用诸如 Ant 之类的构建工具来构建(编译/jar/签名等)小程序。 It might take an hour or so to write the build script & check it, but thereafter you can build the project by a few keystrokes and a couple of seconds.编写构建脚本并检查它可能需要一个小时左右的时间,但此后您可以通过几个按键和几秒钟的时间构建项目。

It would be quite annoying if I always have to extract and sign my jar if I want to test my Aplet如果我想测试我的 Aplet,如果我总是必须提取并签署我的 jar,那会很烦人

I'm not sure what you mean there.我不确定你的意思。 Where does the 'extract' come into it? “提取物”从何而来? In case I was not clear, a sand-boxed applet can load resources this way, from any Jar that is mentioned in the archive attribute.如果我不清楚,沙盒小程序可以以这种方式从archive属性中提到的任何 Jar 加载资源。 Another thing you might do, is to separate the resource Jar(s) from the applet Jar.您可能会做的另一件事是将资源 Jar 与小程序 Jar 分开。 Resources typically change less than code, so your build might be able to take some shortcuts.资源通常比代码更改更少,因此您的构建可能会采取一些捷径。

I think I really have to consider putting my Images into a seperate directory outside the jar.我想我真的必须考虑将我的图像放入 jar 之外的单独目录中。

If you mean on the server, there will be no practical way to get a listing of the image files short of help from the server.如果您的意思是在服务器上,那么在没有服务器帮助的情况下,将没有实用的方法来获取图像文件的列表。 EG Some servers are insecurely set up to produce an HTML based 'file list' for any directory with no default file (such as an index.html). EG 一些服务器设置不安全,无法为任何没有默认文件的目录(例如 index.html)生成基于 HTML 的“文件列表”。


I have only got one jar, in which my classes, images and sounds are.我只有一个 jar,我的课程、图像和声音都在其中。

OK - consider moving the sounds & images into a separate Jar.好的 - 考虑将声音和图像移动到单独的 Jar 中。 Or at the very least, put them in the Jar with 'no compression'.或者至少,将它们放入“无压缩”的 Jar 中。 While Zip comression techniques work well with classes, they are less efficient at compressing (otherwise already compressed) media formats.虽然 Zip 压缩技术适用于类,但它们在压缩(否则已经压缩)媒体格式时效率较低。

I have to sign it because I use the "Preferences" class to save user settings."我必须签名,因为我使用“首选项”class 来保存用户设置。”

There are alternatives to the Preferences for applets, such as cookies.小程序的Preferences有替代方案,例如 cookies。 In the case of plug-in 2 architecture applet, you can launch the applet (still embedded in the browser) using Java Web Start .在插件 2 架构小程序的情况下,您可以使用Java Web 启动小程序(仍然嵌入在浏览器中)。 JWS offers the PersistenceService. JWS 提供 PersistenceService。 Here is my small demo.这是我的小演示。 of the PersistenceService .的 PersistenceService

Speaking of JWS, that brings me to: Are you absolutely certain this game would be better as an applet, rather than an app (eg using a JFrame ) launched using JWS?说到 JWS,这让我想到:你绝对确定这款游戏作为一个小程序而不是一个使用 JWS 启动的应用程序(例如使用JFrame )会更好吗?

Applets will give you no end of stress, and JWS has offered the PersistenceService since it was introduced in Java 1.2. Applet 会给您带来无穷无尽的压力,JWS 自从在 Java 1.2 中引入以来就提供了PersistenceService

Here is a solution which should work given that you use Java 7... The "trick" is to use the new file API.这是一个解决方案,如果您使用 Java 7 ... “诀窍”是使用新文件 API,则该解决方案应该可以工作。 Oracle JDK provides a FileSystem implementation which can be used to peek into/modify ZIP files, and that include jars! Oracle JDK 提供了一个FileSystem实现,可用于查看/修改 ZIP 文件,包括 jar!

Preliminary: grab System.getProperty("java.class.path", ".") , split against : ;初步:抓取System.getProperty("java.class.path", ".") ,拆分为: ; this will give you all entries in your defined classpath.这将为您提供定义的类路径中的所有条目。

First, define a method to obtain a FileSystem out of a classpath entry:首先,定义一个从类路径条目中获取FileSystem的方法:

private static final Map<String, ?> ENV = Collections.emptyMap();

//

private static FileSystem getFileSystem(final String entryName)
    throws IOException
{
    final String uri = entryName.endsWith(".jar") || entryName.endsWith(".zip"))
        ? "jar:file:" + entryName : "file:" + entryName;
    return FileSystems.newFileSystem(URI.create(uri), ENV);
}

Then create a method to tell whether a path exists within a filesystem:然后创建一个方法来判断文件系统中是否存在路径:

private static boolean pathExists(final FileSystem fs, final String needle)
{
    final Path path = fs.getPath(needle);
    return Files.exists(path);
}

Use it to locate your directory.使用它来定位您的目录。

Once you have the correct FileSystem , use it to walk your directory using .getPath() as above and open a DirectoryStream using Files.newDirectoryStream() .一旦你有了正确的FileSystem ,使用它来遍历你的目录,使用.getPath()和打开一个DirectoryStream使用Files.newDirectoryStream()

And don't forget to .close() a FileSystem once you're done with it!完成后不要FileSystem .close()一个文件系统!

Here is a sample main() demonstrating how to read all the root entries of a jar:这是一个示例main() ,演示了如何读取 jar 的所有根条目:

public static void main(final String... args)
    throws IOException
{
    final Map<String, ?> env = Collections.emptyMap();
    final String jarName = "/opt/sunjdk/1.6/current/jre/lib/plugin.jar";
    final URI uri = URI.create("jar:file:" + jarName);
    final FileSystem fs = FileSystems.newFileSystem(uri, env);
    final Path dir = fs.getPath("/");
    for (Path entry : Files.newDirectoryStream(dir))
        System.out.println(entry);
}

You can use the PathMatchingResourcePatternResolver provided by Spring.您可以使用 Spring 提供的PathMatchingResourcePatternResolver

public class SpringResourceLoader {

    public static void main(String[] args) throws IOException {
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();

        // Ant-style path matching
        Resource[] resources = resolver.getResources("/Images/**");

        for (Resource resource : resources) {
            System.out.println("resource = " + resource);
            InputStream is = resource.getInputStream();
            BufferedImage img =  ImageIO.read(is);
            System.out.println("img.getHeight() = " + img.getHeight());
            System.out.println("img.getWidth() = " + img.getWidth());
        }
    }
}

I didn't do anything fancy with the returned Resource but you get the picture.我没有对返回的Resource做任何花哨的事情,但你明白了。

Add this to your maven dependency (if using maven):将此添加到您的 maven 依赖项(如果使用 maven):

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>3.1.2.RELEASE</version>
</dependency>

This will work directly from within Eclipse/NetBeans/IntelliJ and in the jar that's deployed.这将直接在 Eclipse/NetBeans/IntelliJ已部署的 jar 中工作。

Running from within IntelliJ gives me the following output:从 IntelliJ 中运行给我以下 output:

resource = file [C:\Users\maba\Development\stackoverflow\Q12016222\target\classes\pictures\BMW-R1100S-2004-03.jpg]
img.getHeight() = 768
img.getWidth() = 1024

Running from command line with executable jar gives me the following output:从命令行使用可执行文件 jar 运行给我以下 output:

C:\Users\maba\Development\stackoverflow\Q12016222\target>java -jar Q12016222-1.0-SNAPSHOT.jar
resource = class path resource [pictures/BMW-R1100S-2004-03.jpg]
img.getHeight() = 768
img.getWidth() = 1024

I think you can directly access resources in ZIP/JAR file Please see Tutorial its giving solution to your question我认为您可以直接访问 ZIP/JAR 文件中的资源请参阅教程它为您的问题提供解决方案

How to extract Java resources from JAR and zip archives如何从 JAR 和 zip 档案中提取 Java 资源

Hopes that helps希望有帮助

If I understand your problem you want to check the directory inside the jar and check all the files inside that directory.You can do something like:如果我了解您的问题,您想检查 jar 中的目录并检查该目录中的所有文件。您可以执行以下操作:

JarInputStream jar = new JarInputStream(new FileInputStream("D:\\x.jar"));
    JarEntry jarEntry ;
    while(true)
        {
         jarEntry = jar.getNextJarEntry();
         if(jarEntry != null)
         {

            if(jarEntry.isDirectory() == false)
            {
        String str = jarEntry.getName();
                if(str.startsWith("weblogic/xml/saaj"))
        {
            anything which comes here are inside weblogic\xml\saaj directory
        }
        }

     }
    }    

What you are looking for here might be the JarEntry list of the Jar... I had done some similar work during grad school... You can get the modified class here ( http://code.google.com/p/marcellodesales-cs-research/source/browse/trunk/grad-ste-ufpe-brazil/ptf-add-on-dev/src/br/ufpe/cin/stp/global/filemanager/JarFileContentsLoader.java ) Note that the URL contains an older Java class not using Generics...您在此处查找的可能是 Jar 的 JarEntry 列表...我在研究生期间做过一些类似的工作...您可以在此处获取修改后的 class ( Z80791B3AE7002CB88C246876D9FAAAA29DC40AB61DZ) -cs-research/source/browse/trunk/grad-ste-ufpe-brazil/ptf-add-on-dev/src/br/ufpe/cin/stp/global/filemanager/JarFileContentsLoader.java )请注意,ZE6B391A8D2C4D45902A23A8B68Z较旧的 Java class 不使用 Generics...

This class returns a set of URLs with the protocol "jar:file:/" for a given token...此 class 为给定令牌返回一组具有协议“jar:file:/”的 URL...

package com.collabnet.svnedge.discovery.client.browser.util;

import java.io.IOException;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class JarFileContentsLoader {

    private JarFile jarFile;

    public JarFileContentsLoader(String jarFilePath) throws IOException {
        this.jarFile = new JarFile(jarFilePath);
    }

    /**
     * @param existingPath an existing path string inside the jar.
     * @return the set of URL's from inside the Jar (whose protocol is "jar:file:/"
     */
    public Set<URL> getDirEntries(String existingPath) {
        Set<URL> set = new HashSet<URL>();
        Enumeration<JarEntry> entries = jarFile.entries();
        while (entries.hasMoreElements()) {
            String element = entries.nextElement().getName();
            URL url = getClass().getClassLoader().getResource(element);
            if (url.toString().contains("jar:file")
                    && !element.contains(".class")
                    && element.contains(existingPath)) {
                set.add(url);
            }
        }
        return set;
    }

    public static void main(String[] args) throws IOException {
        JarFileContentsLoader jarFileContents = new JarFileContentsLoader(
                "/u1/svnedge-discovery/client-browser/lib/jmdns.jar");
        Set<URL> entries = jarFileContents.getDirEntries("impl");
        Iterator<URL> a = entries.iterator();
        while (a.hasNext()) {
            URL element = a.next();
            System.out.println(element);
        }
    }

}

The output would be: output 将是:

jar:file:/u1/svnedge-discovery/client-browser/lib/jmdns.jar!/javax/jmdns/impl/constants/
jar:file:/u1/svnedge-discovery/client-browser/lib/jmdns.jar!/javax/jmdns/impl/tasks/state/
jar:file:/u1/svnedge-discovery/client-browser/lib/jmdns.jar!/javax/jmdns/impl/tasks/resolver/
jar:file:/u1/svnedge-discovery/client-browser/lib/jmdns.jar!/javax/jmdns/impl/
jar:file:/u1/svnedge-discovery/client-browser/lib/jmdns.jar!/javax/jmdns/impl/tasks/

May the following code sample can help you可能以下代码示例可以帮助您

   Enumeration<URL> inputStream = BrowserFactory.class.getClassLoader().getResources(".");
        System.out.println("INPUT STREAM ==> "+inputStream);
        System.out.println(inputStream.hasMoreElements());
        while (inputStream.hasMoreElements()) {
            URL url = (URL) inputStream.nextElement();
            System.out.println(url.getFile());
        }

IF you really want to treat JAR files like directories, then please have a look at TrueZIP 7 .如果您真的想将 JAR 文件视为目录,请查看TrueZIP 7 Something like the following might be what you want:类似以下的内容可能是您想要的:

URL url = ... // whatever
URI uri = url.toURI();
TFile file = new TFile(uri); // File-look-alike in TrueZIP 7
if (file.isDirectory) // true for regular directories AND JARs if the module truezip-driver-file is on the class path
    for (TFile entry : file.listFiles()) // iterate top level directory
         System.out.println(entry.getPath()); // or whatever

Regards, Christian问候, 克里斯蒂安

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM