Как извлекать Java-ресурсы из jar- и zip-архивов
( Джон Д. Митчелл, Артур Чои )
Вы новичок в работе с jar-файлами? Этот класс поможет Вам!
Обзор
Упаковка разных Java-ресурсов в Java-архив (jar-файл) — превосходный способ уменьшить время загрузки, повысить безопасность и улучшить управляемость. Этот совет показывает, как легко извлечь ресурсы из jar-файлов для собственного использования. (В оригинальной версии на английском языке 1300 слов)
- Загрузка GIF-изображения
- Замечание о названиях
- Как это работает
- Упражнения для читателя
- Заключение
- Об авторах
- Ресурсы
Большинство программистов на 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-файл большой, может не хватить памяти, чтобы загрузить все файлы во время построения.
- Вместо простого общего метода доступа вроде getResource() , мы могли бы предоставлять специфичные методы доступа, соответствующие определённым ресурсам, — например, getImage() , который возвращает объект Java Image , getClass() , который возвращает объект Java Class (с помощью специализированного загрузчика классов), и так далее. Если jar-файл достаточно небольшой, мы могли бы предварительно собрать все ресурсы на основании их расширений (.gif, .class, и т.д.).
- Некоторые методы могли бы предоставлять информацию о самом данном jar-файле (в основном, обертка вокруг ZipFile ), включая: количество вхождений jar/zip; перечислитель, возвращающий все имена ресурсов; методы доступа, возвращающие длину (и другие атрибуты) отдельного вхождения; метод доступа, позволяющий создавать индекс, и др.
- JarResources можно расширить для использования апплетами. Используя параметры апплета и класс URLConnection , содержимое jar-файлов можно загружать из сети, а не открывать архивы как локальные файлы. Кроме того, мы можем расширить этот класс как особый обработчик Java-содержимого.
Заключение
Если Вы стремились узнать, как извлекать изображения из 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.
Ресурсы
- Файл класса
JarResources.java
:
http://www.javaworld.com/javatips/javatip49/JarResources.java - Документация по jar-файлам:
http://www.javasoft.com/products/jdk/1.1/docs/guide/jar/ - Дополнительный совет по архивированию в Java: «Использование файлов архивов
для ускорения загрузки апплетов»:
http://www.javaworld.com/javatips/jw-javatip21.html
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
