Получение каталога внутри .jar - PullRequest
7 голосов
/ 29 апреля 2011

Я пытаюсь получить доступ к каталогу внутри моего файла JAR.Я хочу просмотреть все файлы внутри самого каталога.Я пытался, например, используя следующее:

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

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

Если я тестирую этот апплет, он работает хорошо.Но как только я помещаю содержимое в банку, это происходит не по нескольким причинам.Если я использую этот код, URL всегда указывает вне jar, поэтому я должен поместить туда каталог Images.Но если я использую new File(imagesDirectoryURL.toURI());, он не будет работать внутри банки, потому что я получаю ошибку URI not hierarchical.Я уверен, что каталог существует внутри банки.Как я могу получить содержимое Images внутри банки?

Ответы [ 8 ]

5 голосов
/ 29 апреля 2011

Пути в Jars - это пути, а не фактические каталоги, так как вы можете использовать их в файловой системе.Чтобы получить все ресурсы в пределах определенного пути файла Jar:

  • Получите URL, указывающее на Jar.
  • Получите InputStream из URL.
  • Создайте ZipInputStream из InputStream.
  • Итерируйте каждый ZipEntry, ища совпадения с нужным путем.

... смогу ли я протестировать свой апплет, когда его нет внутри этой банки?Или мне придется запрограммировать два способа получения моих изображений?

ZipInputStream не будет работать с незанятыми ресурсами в каталогах файловой системы.Но тогда я настоятельно рекомендую использовать инструмент сборки, такой как Ant, для сборки (компилировать / jar / sign и т. Д.) Апплета.Написание сценария сборки и проверка его может занять около часа, но после этого вы можете построить проект несколькими нажатиями клавиш и несколькими секундами.

Это было бы довольно раздражающим, если я всегдаМне нужно достать и подписать мою банку, если я хочу проверить свой аплет

Я не уверен, что вы имеете в виду.Откуда берется «экстракт»?В случае, если мне было непонятно, апплет в песочнице может загружать ресурсы таким образом из любого Jar-файла, упомянутого в атрибуте archive.Еще одна вещь, которую вы можете сделать, это отделить ресурс Jar от апплета Jar.Ресурсы, как правило, меняются меньше, чем код, поэтому ваша сборка может использовать несколько ярлыков.

Я думаю, что мне действительно нужно рассмотреть возможность размещения моих изображений в отдельном каталоге вне jar.

Если вы имеете в виду на сервере, не будет практического способа получить список файлов изображений без справки с сервера.Например, некоторые серверы небезопасно настроены на создание «списка файлов» на основе HTML для любого каталога без файла по умолчанию (например, index.html).


У меня есть только одна банка, в котором мои классы, изображения и звуки.

ОК - рассмотрите возможность перемещения звуков и изображений в отдельную банку.Или, по крайней мере, положить их в банку без сжатия.Хотя методы сжатия Zip хорошо работают с классами, они менее эффективны при сжатии (в противном случае уже сжатых) форматов мультимедиа.

Я должен подписать его, поскольку я использую класс «Предпочтения» для сохранения пользовательских настроек."

Существуют альтернативы Preferences для апплетов, например куки. В случае апплета архитектуры с плагином 2 вы можете запустить апплет (все еще встроенный в браузер), используя Java Web Start . JWS предлагает сервис PersistenceService. Вот моя маленькая демонстрация сервиса PersistenceService .

Говоря о JWS, я узнаю: Вы Абсолютно точно эта игра будет лучше в качестве апплета, чем приложения (например, использующего JFrame), запущенного с использованием JWS?

Апплеты не дадут вам конца стрессу, и JWS предложилаPersistenceService с момента его появления в Java 1.2.

4 голосов
/ 15 марта 2014

Вот решение, которое должно работать, если вы используете Java 7 ... «Хитрость» заключается в использовании нового файлового API. Oracle JDK предоставляет реализацию FileSystem, которую можно использовать для просмотра / изменения ZIP-файлов и которая включает в себя jars!

Предварительно: захват System.getProperty("java.class.path", "."), разделение против :; это даст вам все записи в вашем определенном пути к классам.

Сначала определите метод для получения 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);
}

Затем создайте метод, чтобы определить, существует ли путь в файловой системе:

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

Используйте его, чтобы найти свой каталог.

Как только вы получите правильный FileSystem, используйте его, чтобы пройтись по каталогу, используя .getPath(), как указано выше, и откройте DirectoryStream, используя Files.newDirectoryStream().

И не забудьте .close() a FileSystem, как только вы закончите с этим!

Вот пример main(), демонстрирующий, как прочитать все корневые записи в банке:

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);
}
1 голос
/ 18 августа 2012

Вы можете использовать PathMatchingResourcePatternResolver, предоставленный Spring.

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

Я не делал ничего необычного с возвращенным Resource, но вы получите картину.

Добавьте это к вашей зависимости maven (если используете maven):

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

Это будет работать напрямую из Eclipse / NetBeans / IntelliJ и в развернутом банке.

Запуск из IntelliJ дает мне следующий вывод:

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

Запуск из командной строки с исполняемым файлом jar дает мне следующий вывод:

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
0 голосов
/ 03 мая 2011

Если вы действительно хотите относиться к JAR-файлам как к каталогам, тогда посмотрите на TrueZIP 7 .Что-то вроде следующего может быть то, что вы хотите:

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

С уважением, Кристиан

0 голосов
/ 29 апреля 2011

Может следующий пример кода может помочь вам

   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());
        }
0 голосов
/ 29 апреля 2011

Здесь вы можете найти список JarEntry Jar ... Я проделал похожую работу в аспирантуре ... Вы можете получить модифицированный класс здесь (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) Обратите внимание, что URL содержит старый класс Java, не использующий Generics ...

Этот класс возвращает набор URL с протоколом "jar: file: /" для данного токена ...

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

}

Вывод будет:

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/
0 голосов
/ 29 апреля 2011

Если я понимаю вашу проблему, вы хотите проверить каталог внутри банки и проверить все файлы в этом каталоге. Вы можете сделать что-то вроде:

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

     }
    }    
0 голосов
/ 29 апреля 2011

Я думаю, что вы можете получить прямой доступ к ресурсам в ZIP / JAR-файле. См. Учебное пособие, в котором вы найдете решение вашего вопроса

Как извлечь ресурсы Java из JAR и zip-архивов

Надежды, которые помогают

...