Java 1.1 также добавила классы, поддерживающие чтение и запись сжатых данных в различных форматах. Эти классы были интегрированы в существующую систему ввода-вывода, чтобы обеспечить возможность сжатия.
Однако при этом возник один значительный недостаток: эти новые классы не являются производными от новых классов Reader
и Writer
, а относятся к уровню InputStream
и OutputStream
. Поэтому иногда приходится использовать смесь двух типов потоков (учтите, что можно легко преобразовать между различными типами с помощью InputStreamReader
и OutputStreamWriter
).
Классы сжатия Java 1.1 | Функциональность |
---|---|
CheckedInputStream |
getChecksum() вычисляет контрольную сумму для любого InputStream (не только для распакованного) |
CheckedOutputStream |
getChecksum() вычисляет контрольную сумму для любого OutputStream (не только для распакованного) |
DeflaterOutputStream |
Базовый класс для сжатия данных |
ZipOutputStream |
DeflaterOutputStream , который сжимает данные в формат Zip |
GZIPOutputStream |
DeflaterOutputStream , который сжимает данные в формат GZIP |
InflaterInputStream |
Базовый класс для распаковки данных |
ZipInputStream |
InflaterInputStream , который распаковывает данные, сохраненные в формате Zip |
GZIPInputStream |
InflaterInputStream , который распаковывает данные, сохраненные в формате GZIP |
Интерфейс GZIP очень прост, поэтому он может быть лучшим выбором, если требуется сжать только один поток данных (а не несколько различных потоков). Ниже приведен пример сжатия одного файла:```java //: GZIPcompress.java // Uses GZIP compression in Java 1.1 to compress a file whose name is passed through the command line. import java.io.; import java.util.zip.;
```markdown
Публичный класс GZIPcompress {
публичный статический void основной(строка[] аргументы) {
попробовать {
BufferedReader вход =
новый BufferedReader(
новый FileReader(аргументы[ Yö ]));
BufferedOutputStream выход =
новый BufferedOutputStream(
новый GZIPOutputStream(
новый FileOutputStream("test.gz")));
выводить.println("Запись файла");
целое с;
пока ((с = вход.read()) != -1)
выход.write(с);
вход.close();
выход.close();
выводить.println("Чтение файла");
BufferedReader вход2 =
новый BufferedReader(
новый InputStreamReader(
новый GZIPInputStream(
новый FileInputStream("test.gz"))));
строка s;
пока ((s = вход2.readLine()) != null)
выводить.println(s);
} catch(Исключение e) {
e.printStackTrace();
}
}
}
///:~
Использование сжатия очень прямолинейно — достаточно обернуть выходной поток в `GZIPOutputStream` или `ZipOutputStream`, а входной поток — в `GZIPInputStream` или `ZipInputStream`. Остальные операции выполняются стандартными методами чтения и записи. Однако это типичный пример, когда нам приходится смешивать старые и новые потоки ввода/вывода: данные вводятся через класс `Reader`, а конструктор `GZIPOutputStream` принимает объект типа `OutputStream`, но не `Writer`.
## Раздел 10.8.2 Сохранение нескольких файлов с помощью Zip
Библиотека Java 1.1 с поддержкой Zip кажется более полной. Она позволяет удобно сохранять несколько файлов. Даже существует отдельный класс для упрощения чтения Zip-файлов. Эта библиотека использует стандартный формат Zip, поэтому она хорошо работает со всеми распространенными компрессорами и декомпрессорами на Интернете. В этом примере используется тот же формат, что и в предыдущем, но он позволяет контролировать произвольное количество параметров командной строки. Кроме того, этот пример демонстрирует использование класса Checksum
для вычисления и проверки контрольной суммы файла (Checksum
). Можно выбрать между двумя типами контрольной суммы: Adler32
(быстрее) и CRC32
(медленнее, но более точный).
//: ZipCompress.java
// Использует сжатие Zip Java 1.1 для сжатия
// любого количества файлов, чьи имена передаются
// в качестве параметров командной строки.
import java.io.*;
import java.util.*;
import java.util.zip.*;
``````java
public class ZipCompress {
public static void main(String[] args) {
try {
FileOutputStream f =
new FileOutputStream("test.zip");
CheckedOutputStream csum =
new CheckedOutputStream(f, new Adler32());
ZipOutputStream out =
new ZipOutputStream(new BufferedOutputStream(csum));
out.setComment("A test of Java Zipping");
// Невозможно прочитать вышеуказанное примечание, хотя
for (int i = 0; i < args.length; i++) {
System.out.println("Запись файла " + args[i]);
BufferedReader in =
new BufferedReader(new FileReader(args[i]));
out.putNextEntry(new ZipEntry(args[i]));
int c;
while ((c = in.read()) != -1)
out.write(c);
in.close();
}
out.close();
// Контрольная сумма действительна только после закрытия файла!
System.out.println("Контрольная сумма: " +
csum.getChecksum().getValue());
// Теперь извлекаем файлы:
System.out.println("Чтение файла");
FileInputStream fi =
new FileInputStream("test.zip");
CheckedInputStream csumi =
new CheckedInputStream(fi, new Adler32());
ZipInputStream in2 =
new ZipInputStream(new BufferedInputStream(csumi));
ZipEntry ze;
System.out.println("Контрольная сумма: " +
csumi.getChecksum().getValue());
while ((ze = in2.getNextEntry()) != null) {
System.out.println("Чтение файла " + ze);
int x;
while ((x = in2.read()) != -1)
System.out.write(x);
}
in2.close();
// Альтернативный способ открытия и чтения
// архива ZIP:
ZipFile zf = new ZipFile("test.zip");
Enumeration e = zf.entries();
while (e.hasMoreElements()) {
ZipEntry ze2 = (ZipEntry) e.nextElement();
System.out.println("Файл: " + ze2);
// ... и извлечение данных так же как раньше
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
///:~Для каждого файла, который требуется добавить в архив, следует вызвать `putNextEntry()`, передав ему объект `ZipEntry`. Объект `ZipEntry` предоставляет полный интерфейс для получения и установки всех данных, связанных с конкретным входом (entry) внутри ZIP-файла: имя, размер до и после сжатия, дата, контрольная сумма CRC, дополнительные поля, комментарий, метод сжатия и является ли этот вход директорией и т. д. Однако, хотя формат ZIP позволяет устанавливать пароли, библиотека ZIP в Java не поддерживает эту возможность. Кроме того, хотя `CheckedInputStream` и `CheckedOutputStream` поддерживают как `Adler32`, так и `CRC32` контрольные суммы, интерфейс `ZipEntry` поддерживает только CRC.
Это ограничение базового формата ZIP препятствует использованию более быстрого алгоритма Adler32
.
Чтобы распаковать файлы, ZipInputStream
предоставляет метод getNextEntry()
, который может вернуть следующий ZipEntry
, если это возможно. В качестве более простого подхода можно использовать объект ZipFile
, который имеет метод entries()
, возвращающий Enumeration
(перечисление) для ZipEntry
.
Для чтения контрольной суммы необходимо иметь доступ к связанному объекту Checksum
. Здесь сохранены ссылки на объекты CheckedOutputStream
и CheckedInputStream
. Однако можно также иметь только ссылку на объект Checksum
.
Один из запутанных методов в потоках ZIP является setComment()
. Как показано выше, мы можем установить комментарий при записи файла, но нет способа получить комментарий из ZipInputStream
. Похоже, что полная поддержка комментариев возможна только через ZipEntry
для каждого отдельного входа.
Конечно, использование GZIP или ZIP-библиотек не ограничивается только файлами — можно сжимать любое содержимое, включая данные, отправляемые через сетевые соединения.
jar
) УтилитаФормат ZIP также используется в формате JAR (Java ARchive) файлов, введенном в Java 1.1. Эта форма файла предназначена для объединения нескольких файлов в один сжатый файл, аналогично ZIP. Однако, как и всё остальное в Java, JAR-файлы являются кросс-платформенными, поэтому нет необходимости беспокоиться о платформозависимых вопросах. Вместе со звуковыми и графическими файлами, в JAR-файле могут находиться и классовые файлы. При работе с интернет-приложениями JAR-файлы оказываются особенно полезными. До появления JAR-файлов веб-браузеры должны были многократно обращаться к веб-серверу для загрузки всех файлов, составляющих "小程序" (апплет). Кроме того, каждый файл был незакомпрессированным. Однако после объединения всех этих файлов в один JAR-файл требуется всего одно обращение к удалённому серверу. При этом благодаря использованию компрессии все данные можно получить быстрее. К тому же каждое входное содержание (элемент) в JAR-файле может быть защищено цифровой подписью (подробнее см. документацию Java для пользователей).JAR-файл состоит из серии файлов, сжатых в формате Zip, а также содержит манифест, который описывает все эти файлы (можно создать свой манифест; если этого не сделать, то программа jar
сделает это за вас). Дополнительную информацию о JAR-манифестах можно найти в онлайн-документации.Программа jar
поставляется вместе с JDK от Oracle и может автоматически сжимать файлы по вашему выбору. Вызовите её следующей командой:
jar [опции] имя_файла [манифест] входной_файл
Опции представлены рядом букв (не требуется указывать дефис или любые другие знаки):
c Создание нового или пустого архива
t Вывод содержимого архива
x Распаковка всех файлов
u Распаковка указанного файла
f Указывает, что вы предоставите имя файла. Если этот параметр пропущен, jar считает, что его входные данные приходят из стандартного ввода; либо при создании файла, выходные данные будут отправлены в стандартный вывод
m Указывает, что первый параметр будет именем пользовательского манифеста
v Генерация подробного вывода, предоставляющего детальное описание работы программы jar
e Добавление главного класса в манифест
O Сохранение файлов без сжатия (для создания JAR-файла, который можно поместить в свой классический путь)
M Отключение автоматического создания манифеста
При подготовке файлов для помещения в JAR-файл, если включён подкаталог, он будет автоматически добавлен, включая все свои подкаталоги, и так далее. Информация о путях также сохраняется.
Ниже приведены некоторые типичные вызовы программы jar
:
jar cf myJarFile.jar *.class
Создание JAR-файла с именем myJarFile.jar
, содержащего все файлы .class
в текущем каталоге, а также автоматически созданного манифеста.```
jar cmf myJarFile.jar myManifestFile.mf *.class
Аналогичным образом, но с добавлением пользовательского манифеста с именем `myManifestFile.mf`.
jar tf myJarFile.jar
Вывод списка всех файлов внутри JAR-файла `myJarFile.jar`.
jar tvf myJarFile.jar
Добавление флага `verbose` (подробный), чтобы предоставить более подробную информацию о файлах внутри JAR-файла `myJarFile.jar`.
jar cvf myApp.jar audio classes image
Предположим, что `audio`, `classes` и `image` являются подкаталогами, таким образом, все подкаталоги объединяются в файл `myApp.jar`. Также используется флаг `verbose`, чтобы получить более подробную информацию о работе программы `jar`.
Если JAR-файл создан с использованием опции `-O`, его можно поместить в свой классовый путь (`CLASSPATH`):
```markdown
CLASSPATH="lib1.jar;lib2.jar;"
Java сможет искать цели в файлах lib1.jar
и lib2.jar
.
Функционал инструмента jar
менее богатым по сравнению с инструментом zip
. Например, нельзя добавлять или обновлять файлы внутри существующего JAR-файла, можно создать новый JAR-файл заново. Кроме того, нельзя перемещать файлы внутрь JAR-файла и затем удалять их. Однако, JAR-файл, созданный на одной платформе, может быть прочтен без проблем на любой другой платформой с помощью инструмента jar
(что иногда вызывает проблемы у инструмента zip
).
Как вы увидите в главе 13, мы также используем JAR для упаковки Java Beans.
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )