Как добавить файл в архив jar

Обновлено: 02.07.2024

В Java для чтения Zip-архивов применяется класс ZipInputStream. В каждом таком архиве всегда требуется просматривать отдельные записи (entries). Метод getNextEntry возвращает описывающий запись объект типа ZipEntry. Метод read класса ZipInputStream изменяется так, чтобы он возвращал -1 в конце текущей записи (а не просто в конце Zip-файла). Далее вызывается метод closeEntry для получения возможности перехода к считыванию следующей записи.

ZipInputStream zin = new ZipInputStream(new FileInputStream(zipName));
ZipEntry entry;
while ((entry = zin.getNextEntry()) != null) //анализ entry
//считывание содежимого
zin.closeEntry();
>
zin.close();

Для считывания содержимого конкретной записи из Zip-файла эффективнее использовать не стандартный метод read, а методы какого-то обладающего большими возможностями потокового фильтра. Например, для считывания текстового файла, находящегося внутри Zip-архива, можно применить следующий цикл:

Scanner in = new Scanner(zin);
while (in.hasNextLine()) //выполнение операций с in.nextLine()

Запись в Zip-архив.

Для записи Zip-файла применяется класс ZipOutputStream. Для каждой записи, которую требуется поместить в Zip-файл, создается объект ZipEntry. Желаемое имя для файла передается конструктору ZipEntry; тот устанавливает устанавливает остальные параметры, вроде даты создания файла и метода распаковки. При желании эти параметры могут переопределяться. Далее вызывается метод putNextEntry класса ZipOutputStream для начала процесса записи нового файла. После этого данные самого файла отправляются потоку ZIp. По завершении вызывается метод closeEntry. Затем все эти действия выполняются повторно для всех остальных файлов, которые требуется сохранить в Zip-архиве. Ниже приведена общая схема необходимого кода:

FileOutputStream fout = new FileOutputStream("test.zip");
ZipOutputStream zout = new ZipoutputStream(fout);
//Для всех файлов:
ZipEntry ze = new ZupEntry("имя файла");//Имя файла - имя файла в архиве
zout.putNextEntry(ze);
//отправка данных в поток zout
zout.closeEntry();
>
zout.close();

Сжатие объектов с сохранением

Имеется класс "Работник" реализующий интерфейс для сериализации:

public class Employee implements Serializable

String name;
int age;
int salary;

public Employee(String name, int age, int salary) this.name = name;
this.age = age;
this.salary = salary;
>

public void print() System.out.println("Record for: " + name);
System.out.println("Name: " + name);
System.out.println("Age: " + age);
System.out.println("Salary: " + salary);
>
>

Сохранить объекты данного класса мы можем следующим кодом:

import java.io.*;
import java.util.zip.*;

public class SaveEmployee

public static void main(String argv[]) throws
Exception Employee sarah = new Employee("S. Jordan", 28,
56000);
Employee sam = new Employee("S. McDonald", 29,
58000);
FileOutputStream fos = new FileOutputStream("db");
GZIPOutputStream gz = new GZIPOutputStream(fos);
ObjectOutputStream oos = new ObjectOutputStream(gz);
oos.writeObject(sarah);
oos.writeObject(sam);
oos.flush();
oos.close();
fos.close();
>
>

Здесь всё просто, данные мы сохраняем в файл (FileOutputStream) перед этим сжав их (GZIPOutputStream), а в роли данных выступают объекты (ObjectOutputStream).

Загрузить сохраненные сжатые объекты также просто как и сохранить их:

import java.io.*;
import java.util.zip.*;

public class ReadEmployee

public static void main(String argv[]) throws
Exception FileInputStream fis = new FileInputStream("db");
GZIPInputStream gs = new GZIPInputStream(fis);
ObjectInputStream ois = new ObjectInputStream(gs);
Employee sarah = (Employee) ois.readObject();
Employee sam = (Employee) ois.readObject();
sarah.print();
sam.print();
ois.close();
fis.close();
>
>

Данные считываются из файла (FileInputStream), файлы являются сжатыми (GZIPInputStream), данными являются объекты (ObjectInputStream).

Также можно обмениваться сжатыми объектами между сервером/клиентом (с использованием сокетов), ниже представлен код отправки сжатого объекта клиенту:

GZIPOutputStream gzipout =
new GZIPOutputStream(socket.getOutputStream());
ObjectOutputStream oos =
new ObjectOutputStream(gzipout);
oos.writeObject(obj);
gzipos.finish();

Ниже представлен код по получению и декомпрессии данных объекта от сервера:

в настоящее время я извлекаю содержимое файла war, а затем добавляю некоторые новые файлы в структуру каталогов, а затем создаю новый файл war.

все это делается программно с Java-но мне интересно, не было бы более эффективным скопировать файл war, а затем просто добавить файлы - тогда мне не пришлось бы ждать, пока война расширится, а затем снова должна быть сжата.

Я не могу найти способ сделать это в документации Хотя или любые онлайн-примеры.

кто-нибудь может дать некоторые подсказки или указатели?

кто-нибудь имеет опыт или отзывы о TrueZip или может рекомендовать другие подобные библиотеки?

в Java 7 мы получили Файловая Система Zip что позволяет добавлять и изменять файлы в zip (jar, war) без ручной переупаковки.

мы можем напрямую записывать в файлы внутри zip-файлов, как в следующем примере.

Как уже упоминалось, невозможно добавить контент к существующему zip (или war). Тем не менее, можно создать новый zip на лету без временной записи извлеченного содержимого на диск. Трудно догадаться, насколько быстрее это будет, но это самый быстрый, который вы можете получить (по крайней мере, насколько я знаю) со стандартной Java. Как упоминал Карлос Тасада, SevenZipJBindings может выжать из вас несколько дополнительных секунд, но перенос этого подхода на SevenZipJBindings все равно будет быстрее, чем использование временных файлов с той же библиотекой.

вот некоторый код, который записывает содержимое существующего zip (war.ZIP) и добавляет дополнительный файл (ответ.txt) на новый zip (append.промелькнуть.) Все, что требуется, это Java 5 или более поздняя версия, никаких дополнительных библиотек не требуется.

У меня было аналогичное требование когда - то назад-но это было для чтения и записи zip-архивов (.формат войны должен быть похож). Я попытался сделать это с существующими потоками Java Zip, но нашел часть записи громоздкой - особенно когда каталоги, в которых участвуют.

Я рекомендую вам попробовать TrueZIP (open source - Apache style licensed) библиотека, которая предоставляет любой архив как виртуальную файловую систему, в которой вы можете читать и писать как обычно файловая система. Он работал как шарм для меня и значительно упростило мое развитие.

вы можете использовать этот кусок кода я написал

Майкл Крауклис прав, что вы не можете просто "добавить" данные в файл войны или zip-файл, но это не потому, что в файле войны есть указание "конец файла". Это потому, что формат war (zip) включает в себя каталог, который обычно присутствует в конце файла, который содержит метаданные для различных записей в файле war. Наивное добавление к файлу war не приводит к обновлению каталога, и поэтому у вас просто есть файл war с добавленным к нему мусором.

необходим интеллектуальный класс, который понимает формат и может читать + обновлять файл war или zip-файл, включая соответствующий каталог. DotNetZip делает это без распаковки / повторного сжатия неизмененных записей, как вы описали или пожелали.

Как говорит Чизо, нет никакого способа сделать это. AFAIK передние концы zip делают то же самое, что и вы внутри.

в любом случае, если вы беспокоитесь о скорости извлечения/сжатия всего, вы можете попробовать SevenZipJBindings библиотека.

Я покрыл эту библиотеку в моем блог несколько месяцев назад (извините за авто-продвижение). Как пример, извлечение 104mb zip-файла с помощью java.утиль.zip занял у меня 12 секунд, при использовании этой библиотеки занимает 4 секунды.

в обеих ссылках вы можете найти примеры того, как его использовать.

надеюсь, что это помогает.

используя режим добавления на любом виде структурированные данные, такие как zip-файлы или tar файлы-это не то, что вы действительно можете ожидайте работы. Этот формат файла имейте внутренний " конец файла" индикация встроена в формат данных.

Если вы действительно хотите пропустить промежуточный шаг un-waring / re-waring, вы можете прочитать файл файла войны, получить все записи zip, а затем написать в новый файл войны " добавление" новые записи, которые вы хотели добавить. Не идеальное, но, по крайней мере, более автоматизированное решение.

еще одно решение: вы можете найти код ниже полезным и в других ситуациях. Я использовал ant таким образом для компиляции каталогов Java, генерации файлов jar, обновления zip-файлов.

Это простой код для получения ответа с помощью сервлета и отправки ответа

это работает 100% , если вы не хотите использовать дополнительные библиотеки .. 1) Во-первых, класс, который добавляет файлы в zip ..

2) Вы можете вызвать его в ваш контроллер ..

вот примеры того, как легко файлы могут быть добавлены к существующему zip с помощью TrueVFS:

TrueVFS, преемник TrueZIP, использует функции Java 7 NIO 2 под капотом, когда это необходимо, но предлагает гораздо больше возможностей как потокобезопасное асинхронное параллельное сжатие.

остерегайтесь также, что Java 7 ZipFileSystem по умолчанию уязвимы для OutOfMemoryError на огромные вложения.

Необходимость включать в jar файл другие jar файлы возникает практически всегда, когда вы используете библиотечные классы.

В таких случаях, а это 99% от всех случаев, используем заголовок Class-Path:

здесь я указал путь к архиву SBPJavaAcc.jar и к архиву firebirdsql-full.jar, оба архива находятся в папке Lib. Разделитель между архивами – пробел. И что же делать с этим Class-Path? Его надо добавить в манифест.

Рассмотрим пример. В качестве библиотечного jar архива задействуем JarFile.jar – это jar файл из предыдущего раздела. И научимся делать jar файлы в среде Eclipse.

Ещё Jar пример

в jar файл включить другой jar файл

Создадим новый проект JarInJar, а в нём пакет myJar:

Создадим в пакете myJar класс MainJar (установите флаг public static void main(String[] args)) и изменим созданный мастером код так:

в jar файл включить другой jar файл

В папке Hilfe сделаем папку Lib, затем, внимание, в проводнике скопируйте файл JarFile.jar из предыдущего проекта и поместите эту копию в нашу папку Lib. Сделать это можно либо прямо в проводнике, либо правой кнопкой по папке Lib -> Paste. Получаем:

Делаем обработчик нажатия на кнопку “Jar пример” (предварительно введите новое поле JarClass jc и укажите импорт import myPack.JarClass). Окончательно получаем:

Итак, что мы имеем? Мы создали класс MainJar, который использует класс JarClass из архивного файла. Это то, что нам нужно. Мы будем делать архив проекта JarInJar, а этот проект использует другой архив: JarFile.jar. Здесь не обойтись без работы с манифестом.

Манифест для jar архива

в jar файл включить другой jar файл

Правой кнопкой по корневой папке проекта New -> File, назовите файл sbp-program.txt.

в jar файл включить другой jar файл

В файл sbp-program.txt вводим текст: Manifest-Version: 1.0
Created-By: SBP-Program
Main-Class: myJar.MainJar
Class-Path: Lib/JARFile.jar
X-COMMENT: Lib folder content was added manually
и переведите курсор на новую строку, это важно. Получаем:

Обратите внимание, на картинке курсор в начале новой строки.

Сохраните проект. Запустите проект на выполнение и убедитесь, что всё работает.

В этой статье я расскажу об основах создания, взаимодействия, проверки и извлечения файлов zip-архива с помощью Java (в частности, OpenJDK 11). Пример кода, используемый в этой статье, выполнен в виде проекта Gradle и размещен в этом репозитории GitHub для запуска и экспериментов. Пожалуйста, будьте осторожны при изменении кода, который удаляет файлы.

Как уже упоминалось, примеры кода здесь написаны с использованием Java 11 и используют ключевое слово var , которое было введено в Java 10, и парадигмы функционального программирования в Java 8, поэтому для их запуска требуется минимальная версия Java 10 как есть.

Содержание

Ключевые классы Java для работы с Zip-архивами

Я чувствую, что это хорошая идея, чтобы начать с определения некоторых известных классов, которые обычно используются при работе с zip-архивами в Java. Эти классы живут либо в java.util.zip или java.nio.файл пакеты.

Общие пути к файлам для примеров кода

Для примера кода я использую два общих каталога для записи и чтения данных в/из которых оба относятся к корню проекта Gradle. Взгляните на связанное репо во введении или, еще лучше, запустите образцы. Просто имейте в виду эти две переменные пути, поскольку они часто используются в качестве начального каталога для входов и выходов.

Вы можете создать экземпляр класса ZipFile и передать ему путь к существующему zip-архиву, который, по сути, открывает его, как и любой другой файл, а затем проверить содержимое, запросив перечисление ZipEntry , содержащееся в нем. Обратите внимание, что Zip-файл реализует Автоклавируемый интерфейс, что делает его отличным кандидатом для попробуйте с ресурсами Java-программную конструкцию, показанную ниже и во всех приведенных здесь примерах.

Запуск проекта Gradle с использованием следующих:

Это дает результат для приложения.показать содержимое Zip метод:

Здесь вы можете видеть, что при этом выводятся все файлы и каталоги в zip-архиве, даже файлы внутри каталогов.

Извлечение Zip-архива

Для извлечения содержимого zip-архива на диск требуется не что иное , как репликация той же структуры каталогов, что и внутри файла ZipFile , которую можно определить с помощью каталога ZipEntry.IS , а затем копирование файлов, представленных в экземплярах ZipEntry , на диск.

Запись файлов непосредственно в Новый Zip-архив

Поскольку запись zip-архива на самом деле не что иное, как запись потока данных в какое-либо место назначения (в данном случае в Zip-файл), то запись данных, например строковых данных, в zip-архив отличается только тем, что вам нужно сопоставить данные, записываемые в ZipEntry экземпляры, добавленные в ZipOutputStream .

Опять же, ZipOutputStream реализует автоклавируемый интерфейс, поэтому его лучше всего использовать с инструкцией try-with-resources. Единственная реальная загвоздка в том, чтобы не забыть закрыть свой ZipEntry , когда вы закончите с каждым из них, чтобы было ясно, когда он больше не должен получать данные.

Архивирование существующего файла в Новый Zip-архив

Если вы скопировали файл на Java до этого, вы, по сути, уже являетесь профессионалом в создании zip-архива из существующего файла (или каталога, если на то пошло). Опять же, единственная реальная разница заключается в том, что вам нужно проявить немного дополнительной осторожности, чтобы убедиться, что вы сопоставляете файлы с соответствующими экземплярами ZipEntry .

Архивирование папки в Новый Zip-архив

Сжатие непустого каталога становится немного сложнее, особенно если вы хотите сохранить пустые каталоги в родительском каталоге. Чтобы сохранить наличие пустого каталога в zip-архиве , вам необходимо обязательно создать запись с разделителем каталогов файловой системы при создании ZipEntry , а затем немедленно закрыть ее.

Git Essentials

Ознакомьтесь с этим практическим руководством по изучению Git, содержащим лучшие практики и принятые в отрасли стандарты. Прекратите гуглить команды Git и на самом деле изучите это!

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

Вывод

В этой статье я обсудил и продемонстрировал современный подход к работе с zip-архивами на Java с использованием чистой Java и без сторонних библиотек. Вы также можете заметить, что я использую несколько более современных функций языка Java, таких как парадигмы функционального программирования и ключевое слово var для переменных, определяемых типом, поэтому, пожалуйста, убедитесь, что вы используете по крайней мере Java 10 при запуске этих примеров.

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

Читайте также: