[an error occurred while processing this directive] IT • archiv :: Print

IT • archiv


[an error occurred while processing this directive]

[an error occurred while processing this directive]

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

[an error occurred while processing this directive](none) [an error occurred while processing this directive](none)[an error occurred while processing this directive] ::
[an error occurred while processing this directive](none)
[an error occurred while processing this directive]([an error occurred while processing this directive] Джон Д. Митчелл, Артур Чои [an error occurred while processing this directive])

[an error occurred while processing this directive](none)

Вы новичок в работе с jar-файлами? Этот класс поможет Вам!

Tips 'N Tricks
PDF versionPDF версия
Обзор
Упаковка разных Java-ресурсов в Java-архив (jar-файл) — превосходный способ уменьшить время загрузки, повысить безопасность и улучшить управляемость. Этот совет показывает, как легко извлечь ресурсы из jar-файлов для собственного использования. (В оригинальной версии на английском языке 1300 слов)

Большинство программистов на Java прекрасно понимают преимущества использования jar-файла для связывания воедино всех ресурсов (т.е. файлов классов, звуков, и изображений), составляющих решение на Java. (Если Вы не знакомы с jar-файлами, обратитесь к разделу «Ресурсы» ниже.). Те, кто только начал включать jar-файлы в набор используемых инструментов, очень часто спрашивают, как можно извлечь изображение из jar-файла. Мы ответим на этот вопрос и дадим класс, делающий исключительно простым извлечение любого ресурса из jar-файла!

Загрузка GIF-изображения

Допустим, у нас есть jar-файл, содержащий множество файлов с gif-изображениями, которые мы хотим использовать в нашем приложении. Вот как мы можем обратиться к файлу изображения из jar-файла, используя JarResources :

     JarResources jar = new JarResources ("Images.jar");
     Image logo =
     Toolkit.getDefaultToolkit().createImage
      (jar.getResource ("logo.gif");

Этот фрагмент кода показывает, что мы можем создать объект JarResources , инициализированный на основе jar-файла, содержащего ресурс, в использовании которого мы заинтересованы, — Images.jar . Мы тогда используем метод getResource() из JarResources , чтобы получить исходные данные из файла logo.gif для метода createImage() из библиотеки AWT.

Замечание о названиях

JarResource — достаточно простой пример того, как можно использовать различные средства Java 1.1 для манипулирования jar- и zip-архивами.

Краткое замечание о названиях. Поддержка архивирования в Java фактически была начата с использования популярного формата архивов zip (См. «Совет по Java: Использование файлов архивов для ускорения загрузки апплетов» ). Так, первоначально при реализации в Java поддержки файлов архивов все классы и прочее помещались в пакет java.util.zip; эти классы обычно начинаются с « Zip ». Но где-то на пути к Java 1.1 было решено сменить имя архива на имеющее непосредственное отношение к Java. Следовательно, то, что мы теперь называем jar-файлами, по существу — zip-файлы.

Как это работает

Важные поля данных для класса JarResources используются для отслеживания и хранения содержимого указанного jar-файла:

public final class JarResources {
    public boolean debugOn=false;
    private Hashtable htSizes=new Hashtable();
    private Hashtable htJarContents=new Hashtable();
    private String jarFileName;

Так, при создании экземпляра класса устанавливается имя jar-файла, а затем вызывается метод init() , который делает всю работу:

    public JarResources(String jarFileName) {
       this.jarFileName=jarFileName;
       init();
    }

Метод init() просто загружает содержимое указанного jar-файла в hashtable (с обращением к нему по имени ресурса).

Это довольно громоздкий метод, поэтому давайте его разделим. Класс ZipFile дает нам базовый доступ к информации заголовка jar/zip-архива. Это похоже на информацию о каталоге в файловой системе. Здесь мы получаем перечисление всех элементов в ZipFile и создаём hashtable под именем htSizes с размером каждого ресурса в архиве:

    private void init(){
       try {
           ZipFile zf=new ZipFile(jarFileName);
           Enumeration e=zf.entries();
           while (e.hasMoreElements()) {
               ZipEntry ze=(ZipEntry)e.nextElement();
                if (debugOn) {
                  System.out.println(dumpZipEntry(ze));
                }
               htSizes.put(ze.getName(),new Integer((int)ze.getSize()));
           }
           zf.close();

Затем мы обращаемся к архиву с помощью класса ZipInputStream . Класс ZipInputStream даёт нам всё необходимое для чтения каждого отдельного ресурса в архиве. Мы читаем точное количество байтов из архива, которые составляют каждый ресурс, и сохраняем эти данные в hashtable с именем htJarContents с доступом по имени ресурса:

           FileInputStream fis=new FileInputStream(jarFileName);
           BufferedInputStream bis=new BufferedInputStream(fis);
           ZipInputStream zis=new ZipInputStream(bis);
           ZipEntry ze=null;
           while ((ze=zis.getNextEntry())!=null) {
              if (ze.isDirectory()) {
                 continue;
              }
              if (debugOn) {
                 System.out.println(

"ze.getName()="+ze.getName()+","+"getSize()="+ze.getSize()
                    );
              }
              int size=(int)ze.getSize();
              // -1 означает неизвестный размер.
              if (size==-1) {
                 size=((Integer)htSizes.get(ze.getName())).intValue();
              }
              byte[] b=new byte[(int)size];
              int rb=0;
              int chunk=0;
              while (((int)size - rb) > 0) {
                  chunk=zis.read(b,rb,(int)size - rb);
                  if (chunk==-1) {
                     break;
                  }
                  rb+=chunk;
              }
              // добавляем в hashtable с внутренними ресурсами
              htJarContents.put(ze.getName(),b);
              if (debugOn) {
                 System.out.println(
                    ze.getName()+"  rb="+rb+
                    ",size="+size+
                    ",csize="+ze.getCompressedSize()
                    );
                }
          }
        } catch (NullPointerException e) {
           System.out.println ("сделано.");
        } catch (FileNotFoundException e) {
           e.printStackTrace();
        } catch (IOException e) {
           e.printStackTrace();
        }
 }

Заметьте, что имя, использованное для идентификации каждого ресурса, это путь к ресурсу в архиве, а не, например, имя класса в пакете — то есть класс ZipEntry из пакета java.util.zip должен именоваться "java/util/zip/ZipEntry" , а не " java.util.zip.ZipEntry" .

Заключительная важная часть кода — тестовый драйвер. Это простое приложение, которое берёт имя jar/zip-архива и имя ресурса. Затем оно пытается найти ресурс в архиве и сообщает об успехе или неудаче:

    public static void main(String[] args) throws IOException {
        if (args.length!=2) {
           System.err.println(
              "использование: java JarResources  "
              );
           System.exit(1);
         }
        JarResources jr=new JarResources(args[0]);
        byte[] buff=jr.getResource(args[1]);
        if (buff==null) {
           System.out.println("Не найдено "+args[1]+".");
        } else {
           System.out.println("Найдено "+args[1]+ "
(length="+buff.length+").");
         }
    }
} // Конец класса JarResources.

Теперь у Вас есть класс, облегчающий использование ресурсов, упакованных в jar-файлах.

Упражнения для читателя

Теперь, когда Вы умеете извлекать ресурсы из архива, вот несколько направлений, которые Вы можете исследовать, изменяя и расширяя класс JarResources :

Заключение

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

Об авторах

Артур Чои в настоящее время работает в IBM программистом-консультантом. Он работал в нескольких компаниях, включая SamSung Network Laboratory и MITRE. Различные проекты, над которыми он работал, это клиент-серверные системы, распределенные вычисления и сетевое управление. Он использовал множество языков в различных операционных системах. Он начал программировать в 1981 г. с ФОРТРАНА IV и КОБОЛА. Позже он перешёл на C и C ++, а также приблизительно два года работал с Java. В сфере его интересов, в основном, Java-приложения в банках данных на базе глобальных сетей и параллельные и распределенные вычисления через Интернет (с использованием агентского программирования).

Джон Митчелл , сотрудник, консультант и руководитель собственной компании, занимался последние десять лет разработкой передового программного обеспечения и консультированием и обучением других разработчиков. Он давал консультации по технологии Java, компиляторам, интерпретаторам, Web-приложениям и торговле через Интернет. Джон — соавтор книги «Making Sense of Java: A Guide for Managers and the Rest of Us» , автор статей в журналах по программированию. В дополнение к написанию статей для колонки Java Tips на JavaWorld он модерирует группы новостей comp.lang.tcl.announce и comp.binaries.geos.

Ресурсы

Reprinted with permission of JavaWorld. Copyright © ITworld.com, Inc., an IDG Communications company.
View the original article at: http://www.javaworld.com/javaworld/javatips/jw-javatip49.html

[an error occurred while processing this directive]
[an error occurred while processing this directive] Перевод на русский © Дмитрий Габинский, 2003
< Вернуться на caйт :: Copyright © 1999 — 2010, IT • archiv.