Извлечение файлов из Jar более эффективно - PullRequest
2 голосов
/ 12 февраля 2009

Я расширяю служебный класс, который объединяет набор изображений и XML-файлы описания. В настоящее время я храню все файлы в каталоге и загружаю их оттуда. Каталог выглядит так:

8.png
8.xml
9.png
9.xml
10.png
10.xml
...
...
50.png
50.xml
...



Вот мой текущий конструктор. Это молниеносно и делает то, что мне нужно. (Я убрал некоторые проверки ошибок, чтобы их было легче читать):

public DivineFont(String directory ) {

    File dir = new File(directory);

    //children is an array that looks like this: '10.fnt', '11.fnt', etc.
    String[] children = dir.list(fntFileFilter);

    fonts = new Hashtable<Integer, AngelCodeFont>(100);

    AngelCodeFont buffer;
    int number;
            String fntFile;
            String imgFile;

    for(int k = 0; k < children.length; k++ ) {
        number = Integer.parseInt( children[k].split("\\.")[0] );
        fntFile = directory + File.separator + number + ".xml";
        imgFile = directory + File.separator + number + ".png";
        buffer = new AngelCodeFont(fntFile, imgFile);

        fonts.put(number, buffer);
    }
}

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

(Это не лучший способ сделать то, что я хочу сделать, это макет, чтобы увидеть, сработала ли идея. Это не сработало. Два цикла for в путь к источнику проблемы, это процесс создания всех тех InputStreams, который замедляет ее)

public DivineFont(String jarFileName ) {

    JarFile jarfile = new JarFile(jarFileName);
    Enumeration<JarEntry> em = jarfile.entries();
    ArrayList<Integer> fontHeights = new ArrayList<Integer>(100);
    for (Enumeration em1 = jarfile.entries(); em1.hasMoreElements(); ) {
        String fileName = em1.nextElement().toString();
        if( fileName.endsWith(".fnt") ) {
            fontHeights.add( Integer.parseInt(fileName.split("\\.")[0] ) );
        }
    }

    fonts = new Hashtable<Integer, AngelCodeFont>(100);

    AngelCodeFont buffer;
    int number;

    for(int k = 0; k < fontHeights.size(); k++ ) {
        number = fontHeights.get(k);
        InputStream fntFileStream = jarfile.getInputStream(jarfile.getEntry(number + ".xml"));
        InputStream pngFileStream = jarfile.getInputStream(jarfile.getEntry(number + ".png"));
        buffer = new AngelCodeFont(String.valueOf(number), fntFileStream, pngFileStream );

        fonts.put(number, buffer);


    }
}


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

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

Также: сжатие вообще не проблема. Единственная причина, по которой я использую банку - это проблема с упаковкой.

Ответы [ 4 ]

4 голосов
/ 12 февраля 2009

Открытие банка - очень дорогая операция. Поэтому вы можете открыть JAR один раз и сохранить экземпляр JarFile в статическом поле. В вашем случае вы также захотите прочитать все записи и сохранить их в хэш-карте для мгновенного доступа к нужному ресурсу.

Другое решение - поместить JAR в путь к классам и использовать

DivineFont.class.getContextClassLoader().getResource*("/8.png");

Запомни "/"! Если вы его опустите, Java будет искать в том же каталоге (пакете), в котором находит файл DivineFont.class.

Получение вещей из classpath оптимизировано до смерти в Java.

1 голос
/ 14 февраля 2009

Ну, я нашел ответ. Ответ на мой оригинальный вопрос был «Неправильный вопрос». Файл Jar не был проблемой, это была библиотека, которую я использовал для загрузки изображений.

Когда я загружал из файловой системы, изображение называлось «38.png» и т. Д. Когда я загружал из Jar, я просто называл его «38».

Класс Image loader внутри библиотеки использует расширение имени файла, чтобы определить, какой загрузчик изображений использовать. Если расширение файла отсутствует, он использует более медленный базовый загрузчик изображений. Когда я изменил эту строку:

buffer = new AngelCodeFont(String.valueOf(number), fntFileStream, pngFileStream );

к этой строке:

buffer = new AngelCodeFont( number + ".png", fntFileStream, pngFileStream );

У нас есть победитель.

Спасибо за помощь, парни. Мне потребовалось несколько часов, чтобы понять это, но если бы не ваши посты, я бы, вероятно, продолжал предполагать, что виновата не Java, а библиотека, которую я использую.

0 голосов
/ 12 февраля 2009

Работа с файлами JAR может быть очень дорогой, и библиотека классов Java уже реализует этот вид загрузки ресурсов (возможно, настолько эффективно, насколько это возможно).

Кроме того, как только вы войдете в webstart, имена ваших jar-файлов будут искажены, так что вам, вероятно, придется в конечном итоге исследовать каждый jar-файл на пути к классам, чтобы загрузить свои ресурсы (я это сделал!

Вместо этого используйте Class.getResourceAsStream (String resourceName) . Я не профилировал его, но не заметил, что он заметно медленнее, чем прямой доступ к файлам.

0 голосов
/ 12 февраля 2009

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

...