Java 1.1 също е добавил класове за четене и писане на файлове в компресиран формат. Те обгръщат съществуващите IO за получаване на възможност за компресиране/декомпресиране на данните.
Един аспект на тези 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
|
DeflaterInputStream който декомпресира от Zip формат
|
GZIPInputStream
|
DeflaterInputStream който декомпресира от GZIP формат
|
Макар и да има много алгоритми за компресия, Zip и GZIP са вероятно най-използваните. Така че лесно може да работите с компресираните си данни чрез множеството налични инструменти.
Проста компресия с GZIP
GZIP интерфейсът е прост и затова може би по-подходящ когато имате едно парче данни за компресиране (в противоположност на множество различни парчета). Ето пример за компресиране на един файл:
//: c10:ZipCompress.java
// Uses Java 1.1 Zip compression to compress
// any number of files whose names are passed
// on the command line.
import java.io.*;
import java.util.*;
import java.util.zip.*;
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");
// Can't read the above comment, though
for(int i = 0; i < args.length; i++) {
System.out.println(
"Writing file " + 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();
// Checksum valid only after the file
// has been closed!
System.out.println("Checksum: " +
csum.getChecksum().getValue());
// Now extract the files:
System.out.println("Reading file");
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("Checksum: " +
csumi.getChecksum().getValue());
while((ze = in2.getNextEntry()) != null) {
System.out.println("Reading file " + ze);
int x;
while((x = in2.read()) != -1)
System.out.write(x);
}
in2.close();
// Alternative way to open and read
// zip files:
ZipFile zf = new ZipFile("test.zip");
Enumeration e = zf.entries();
while(e.hasMoreElements()) {
ZipEntry ze2 = (ZipEntry)e.nextElement();
System.out.println("File: " + ze2);
// ... and extract the data as before
}
} catch(Exception e) {
e.printStackTrace();
}
}
} ///:~
Използването на класовете е праволинейно – просто обгръщате изходния си поток с GZIPOutputStream или ZipOutputStream и входния си поток с GZIPInputStream или ZipInputStream. Всичко друго е обикновено IO четене и писане. Това обаче е хубав пример за случай, когато сте принудени да смесвате старите и новите IO потоци: in използва Reader класове, докато конструктора на GZIPOutputStream може да приеме само OutputStream обект, не Writer обект.
Много файлове със Zip
Библиотеката на Java 1.1 която поддържа Zip формата е много по-богата. С нея може лесно да компресирате множество файлове, даже има отделен клас който прави четенето на Zip файл лесно. Библиотеката използва стандартния Zip формат така че несъмнено е съвместива с данните и инструментите които могат да се изтеглят от Мрежата. Следният пример има същата форма като предишния, но позволява колкото искате аргументи на командния ред. Освен това показва използването на Checksum класовете за изчисление и проверка на контролна сума за файловете. Има два Checksum типа: Adler32 (който е по-бърз) и CRC32 (който е по-бавен но мъничко по-акуратен).
//: c10:ZipCompress.java
// Uses Java 1.1 Zip compression to compress
// any number of files whose names are passed
// on the command line.
import java.io.*;
import java.util.*;
import java.util.zip.*;
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");
// Can't read the above comment, though
for(int i = 0; i < args.length; i++) {
System.out.println(
"Writing file " + 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();
// Checksum valid only after the file
// has been closed!
System.out.println("Checksum: " +
csum.getChecksum().getValue());
// Now extract the files:
System.out.println("Reading file");
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("Checksum: " +
csumi.getChecksum().getValue());
while((ze = in2.getNextEntry()) != null) {
System.out.println("Reading file " + ze);
int x;
while((x = in2.read()) != -1)
System.out.write(x);
}
in2.close();
// Alternative way to open and read
// zip files:
ZipFile zf = new ZipFile("test.zip");
Enumeration e = zf.entries();
while(e.hasMoreElements()) {
ZipEntry ze2 = (ZipEntry)e.nextElement();
System.out.println("File: " + ze2);
// ... and extract the data as before
}
} catch(Exception e) {
e.printStackTrace();
}
}
} ///:~
За да добавите всеки файл към архива трябва да извикате putNextEntry( ) и да му дадете ZipEntry обект. ZipEntry съдържа богат интерфейс който позволява да добавите всичките данни налични в случая в Zip файла: име, дължини компресиран и некомпресиран, дата, CRC сума, допълнителни данни, коментар, метод на компресия и път ако има. Макар и Zip форматът да има начин за даване на парола, това не се поддържа в библиотеката на Java за Zip. И макар че CheckedInputStream и CheckedOutputStream поддържат и Adler32 и CRC32 контролни суми, класът ZipEntry поддържа само интерфейс за CRC. Това е ограничение произтичащо от подлежащия Zip формат, но би могло да ви отклони от използването на по-бъързия Adler32.
За извличане на файлове ZipInputStream има getNextEntry( ) метод който връща следващия ZipEntry ако има такъв. Като по-сбита алтернатива може да прочетете файла със ZipFile обект, който има метод entries( ) с връщане на Enumeration към ZipEntries-ите.
За да четете контролната сума трябва да имате някакъв достъп до асоциирания Checksum обект. Тук се запазват манипулатори към CheckedOutputStream и CheckedInputStream, но също би могъл да бъде и манипулатор на Checksum обект.
Объркващ метод в Zip потоците е setComment( ). Както е показано по-горе, може да се слага коментар когато се пише файл, но няма начин да се възстанови той в ZipInputStream. Коментарите изглежда се поддържат за всяка порция данни чрез ZipEntry.
Разбира се не сте ограничени до файлове когато използвате GZIP или Zip библиотеките – може да компресирате каквите и да е данни, включително за изпращане по Интернет.
Java archive (jar) утилитито
Zip форматът се използва също и в Java 1.1 JAR (Java ARchive) файловия формат, който е начин да се събере група файлове в един компресиран файл, точно както Zip. Само че както всичко в Java, JAR файловете са многоплатформени, така че не трябва да се безпокоите по въпросите за преносимост. Може да се включват и звукови файлове и образи, както и файлове с класове.
JAR файловете са в частност полезни когато имате работа с Internet. Преди JAR файловете вашият Web браузър трябваше да прави множество поръчки към Web сървъра за да получи всичките файлове които съставят даден аплет. Освен това всеки файл беше некомпресиран. Чрез комбинирането на всички необходими за аплета файлове в единствен JAR файл остава необходим само един достъп и освен това обменът е по-бърз поради компресията. И всяка единица в JAR файла може да бъде цифрово подписана за сигурност (вижте Java документацията за подробности).
Един JAR файл се състои от множество зипнати фойлове задедно с “манифест” който ги описва. (Може да създадете ваш собствен файл-манифест; иначе jar програмата ще го направи.) Може да намерите повече за JAR манифестите в онлайн документацията.
jar утилитито което идва с JDK на Sun автоматично компрериса файлове по ваш избор. Вика се с команден ред:
jar [options] destination [manifest] inputfile(s)
Опциите са просто колекция от букви (не са необходими чертички или други подобни). Те са:
-
c
|
Създава нов или празен архив.
|
t
|
Дава съдържанието.
|
x
|
Изважда всички файлове
|
x file
|
Изважда споменатия файл
|
f
|
Казва: “Ще ви дам името на файла.” Ако не използвате това, jar предполага че ще чете от стандратния вход, или, ако създава файл, ще го праща на стандартния изход.
|
m
|
Казва че първият аргумент ще бъде името на потребителския манифестов файл
|
v
|
Създава изход описващ какво прави jar
|
O
|
Само запомня файловете; не ги компресира (използвайте го да създаде JAR файл който може да сложите във вашия път към класовете)
|
M
|
Не създава автоматично манифестен файл
|
Ако файловете които се вкарват в JAR файла включват поддиректория, тя се добавя автоматично, включително всичките поддиректории и т.н. Информацията за пътя също се запазва.
Ето някои типични начини за викане на jar:
jar cf myJarFile.jar *.class
Това създава JAR файл наречен myJarFile.jar който съдържа всичките класови файлове в текущата поддиректория, заедно с автоматично генериран манифестен файл.
jar cmf myJarFile.jar myManifestFile.mf *.class
Като предишния пример, но с добавяне на създаден от потребителя манифест наречен myManifestFile.mf.
jar tf myJarFile.jar
Дава съдържание за myJarFile.jar.
jar tvf myJarFile.jar
Добавя флаг за извеждане на по-подробни сведения за myJarFile.jar.
jar cvf myApp.jar audio classes image
Предполага се, че audio, classes и image са поддиректории, това комбинира всичко в поддиректориите във файл, наречен myApp.jar. ъщо се добавя флаг за повече обратна връзка докато програмата jar работи.
Ако създадете JAR чрез опцията O, този файл може да се сложи в CLASSPATH:
CLASSPATH="lib1.jar;lib2.jar;"
Тогава Java може да търси lib1.jar и lib2.jar за файлове с класове.
Инструментът jar не е толкова полезен калкото zip утилитито. Например не може да добавяте или обновявате файлове в JAR файл; може да създадете JAR файлове само "на празно място". Също не може да премествате файлове в JAR файл, изтривайки ги след вмъкването. Обаче един JAR файл създаден на някаква платформа ще бъде прозрачно четим от jar инструмента на която и да е друга платформа (проблем, който понякога вади душата на zip ютилитата).
Както ще видите в глава 13, JAR файлове се използват и в пакета Java Beans.
Сподели с приятели: |