Library  |  News  |  Hosting  |  Rating  |  Catalogue  |  Forum  |  About 
 
Конкурсы
Java, первое знакомство
За и Против
J2ME
J2EE
J2SE
Справочники
Главная страница
Последняя статья
Архив статей
Авторы статей
Глоссарий



Базовые профили J2ME (06.10.2006)
Первый в истории JetBrains конкурс плагинов к IntelliJ IDEA. Призовой фонд - $25000 (05.09.2006)
IBM WebSphere Community Edition Contest 2006! (10.08.2006)
Управление подсветкой экрана из мидлета (17.05.2006)
Введение в Java Server Faces (01.02.2006)
Работаем с JAR-архивами. (29.12.2005)
Указатели и виртуальные функции в Java (27.10.2005)
Пример использования XPFE/J2EE и SOAP для построения распределенных приложений (19.08.2005)

Главная J2SE

Работаем с JAR-архивами.


J2SE


Иногда возникает потребность в том, чтобы java-программа могла просмотреть содержимое jar-архива, и извлечь его. В Интернете мне не удалось найти много информации по этому вопросу. Хотя, если честно, я не очень-то и искал. Поэтому, решил разобраться во всём сам. Пошарив по документации, мне в голову пришли следующие мысли.

Если мы заранее знаем, что именно нам нужно извлечь из jar-файла, это не составит особого труда.
  1. Для начала нам нужно создать объект класса java.util.jar.JarFile (далее JarFile), и указать для него имя просматриваемого jar-файла.
  2. Затем, создаём объект класса java.util.jar.JarEntry (далее JarEntry) и указываем для него имя файла, который необходимо извлечь.
  3. Для объекта JarFile создаём поток ввода с помощью метода getInputStream(). В качестве аргумента передадим ему объект JarEntry.
  4. Ну а далее, работаем с потоками стандартным образом, используя методы read() и write().
У нас должно получиться что-то вроде:

JarFile jarFile = new JarFile("some_jar_file.jar");
JarEntry jarEntry = new JarEntry("something.smth");
InputStream in = jarFile.getInputStream(jarEntry);
FileOutputStream out = new FileOutputStream(jarEntry.getName());
int t;
while((t = in.read()) != -1)
out.write(t);


Конечно же не забываем включить обработку исключения IOException.

Не правда ли, элементарно? Но что делать, если мы не знаем, что содержится в jar-архиве? Подумав немного над этим вопросом, я ознакомился с классом ZipFile. Ведь JarFile является его наследником. У класса ZipFile есть метод entries(), который возвращает объект интерфейса Enumeration, содержащий имена всех файлов, входящих в архив. Но так как пользоваться этим объектом, мягко говоря, неудобно, то имеет смысл перенести всё содержимое в объект класса Vector. Получаем что-то типа:

Enumeration<JarEntry> entries;
Vector<JarEntry> v;
…
int vc=0;  /* Vector capacity – количество  элементов в векторе v.
Почему-то, метод v.capacity() выдаёт большее число,
чем на самом деле. Разбираться с этим не стал :) */

entries=jarFile.entries();
while(entries.hasMoreElements())
{
  vect.add(entries.nextElement());
  vc++;
}


Замечу сразу, что я писал программу для Java 1.5. Для Java 1.4 и более ранних версий работа с объектами Enumeration и Vector была бы немного другой, немного более трудной. Спасибо Sun Microsystems за облегчение и без того тяжкой участи программистов! :)

Ну а теперь, имея список содержимого jar-архива, мы спокойно можем распаковывать его, не забывая создавать подкаталоги, содержащиеся в архиве. Для этого используем метод mkdir() класса File. Назовём наш метод extract(). Он может иметь следующий вид:

public void extract()
{
  File tmpfile;  /* создаём временный объект, который будет создавать каталоги */
  JarEntry tmpentry;  /* создаём временную ссылку на файл в архиве */
  FileOutputStream out;  /* это и так понятно */
  InputStream in;  /* и это тоже */
  int t;  /* переменная для копирования файла */
  try
  {
    for(int i=0;i<vc;i++)  /* создаём цикл для извлечения файлов
    из архива. Вот нам и пригодилась переменная vc */
    {
      tmpentry=vect.get(i);  /* берём из вектора имя очередного файла или каталога */
      tmpfile=new File(tmpentry.getName());
      if(tmpentry.isDirectory())  /* если tmpfile – каталог, */
      {
        if(!tmpfile.mkdir())  /* то создаём его */
        {
          System.out.println("Can't create directory: "+tmpfile.getName());  /* если он не создаётся, */
          return;  /* выходим из функции */
        }
      }
      else  /* ну а если tmpfile – не каталог, а файл, то спокойно извлекаем его */
      {
        in=jarFile.getInputStream(tmpentry);
        out=new FileOutputStream(tmpfile);
        while((t=in.read())!=-1)
        out.write(t);
        out.close();  /* лучше потоки ввода и вывода закрывать, иначе наша программа */
        in.close();  /* может не сосем корректно работать (некоторые файлы могут теряться) */
      }
    }
  }
  catch(IOException e)  /* обрабатываем исключение */
  {
    System.out.println(e.getMessage());
    e.printStackTrace();  /* это, по-моему, не совсем обязательно */
    System.exit(0);
  }
}


Ура товарищи, мы это сделали! Аналогичным образом можно работать и с zip-архивами. Необходимо только поменять JarFile и JarEntry на ZipFile и ZipEntry соответственно.

На основе этого можно сделать что-нибудь более сложное и подходящее под какие-то конкретные цели. Алгоритм может быть и более оптимально построен. В статье он не совсем оптимален для пущей наглядности.










Об авторе

Должность: Ассистент кафедры ПМиАХП Кузбасского ГТУ

E-mail получателей:



Ваш E-mail:






| Версия для печати | Отправить эту статью другу |


Результаты
Другие опросы



Copyright © JUGA.RU


Rambler's Top100
Java User Group Alliance (Russia)