Донецкий техникум промышленной автоматики

ZIP-архіви в мові Java

ZIP-архіви дозволяють зберігати один і більше файлів в (зазвичай) стислому форматі

ZIP-архіви дозволяють зберігати один і більше файлів в (зазвичай) стислому форматі. У кожного ZIP-архіву є заголовок, содеражащій інформацію на кшталт імені файлу або використовувався для нього методу стиску. В Java для читання ZIP-архівів застосовується клас ZipInputStream. У кожному такому архіві завжди потрібно переглядати окремі записи (entries).

Метод getNextEntry повертає описує запис об'єкт типу ZipEntry. Метод read клас ZipInputStream змінюється так, щоб він повертав -1 в кінці поточний записи (а не просто в кінці ZIP-файлу).

Далі викликається метод closeEntry для отримання можливості переходу до зчитування наступного запису. Нижче приведена типова кодова послідовність для виконання зчитування вмісту ZIP-файлу:

ZipInputStream zin = new ZipInputStream (new FileInputStream (zipname)); ZipEntry entry; while ((entry = zin.getNextEntry ())! = null) {аналіз entry; зчитування вмісту zin; zin.closeEntry (); } Zin.close ();

Для зчитування вмісту конкретної записи з ZIP-файлу ефективніше використовувати не стандартний метод read, а методи якогось володіє великими знаходиться всередині ZIP-архіву, можна застосувати наступний цикл:

Scanner in = new Scanner (in); while (in.hasNextLine ()) виконання якихось операцій з in.nextLine ();

У разі виникнення помилки при зчитуванні ZIP-файлу клас ZipInputStream видає виключення ZipException. Зазвичай подібне відбувається при пошкодженні 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 ZipEntry (имя_файла); zout.putNextEntry (ze); Передавання даних в потік zout; zout.closeEntry (); } Zout.close ();

JAR-файли являють собою ті ж ZIP-файли, але тільки містять записи дещо іншого виду, звані маніфестом. Для зчитування і запису маніфестів застосовуються класи JarInputStream і JarOutputStream.

ZIP-потоки є прекрасним прикладом мощі потокової абстракції. При зчитуванні даних, які зберігаються в стислому вигляді, не потрібно хвилюватися про те, чи будуть вони розпакувати в міру запрашіванія. І джерелом байтів в ZIP-форматах зовсім не обов'язково повинен бути саме файл: ZIP-дані можуть надходити і через мережеве підключення. Насправді, при всякому зчитуванні JAR-файлу завантажувач класів аплета буде зчитувати і розпаковувати дані саме з мережі.

Рис Рис.2. програма ZipTest

програма код якої наведено нижче, дозволяє відкривати ZIP-архів, після чого відображає всі зберігаються всередині нього файли в комбінованому списку в нижній частині екрана. У разі вибору якогось одного з цих файлів вона відображає його вміст в текстовій області, як показано на рис.2.

Ось повний код нашої програми ZipTest.java:

import java.awt. *; import java.awt.event. *; import java.io. *; import java.security.AccessControlContext; import java.util. *; import java.util.List; import java.util.zip. *; import javax.swing. *; public class ZipTest {public static void main (String [] args) {EventQueue.invokeLater (new Runnable () {public void run () {ZipTestFrame frame = new ZipTestFrame (); frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); frame.setVisible (true);}}); }} Class ZipTestFrame extends JFrame {public ZipTestFrame () {setTitle ( "ZipTest"); setSize (DEFAULT_WIDTH, DEFAULT_HEIGHT); // додавання меню і пунктів меню Open (Відкрити) і Exit (Вихід) JMenuBar menuBar = new JMenuBar (); JMenu menu = new JMenu ( "File"); JMenuItem openItem = new JMenuItem ( "Open"); menu.add (openItem); openItem.addActionListener (new ActionListener () {public void actionPerformed (ActionEvent event) {JFileChooser chooser = new JFileChooser (); chooser.setCurrentDirectory (new File ( ".")); int r = chooser.showOpenDialog (ZipTestFrame.this); if (r == JFileChooser.APPROVE_OPTION) {zipname = chooser.getSelectedFile (). getPath (); fileCombo.removeAllItems (); scanZipFile ();}}}); JMenuItem exitItem = new JMenuItem ( "Exit"); menu.add (exitItem); exitItem.addActionListener (new ActionListener () {public void actionPerformed (ActionEvent event) {System.exit (0);}}); menuBar.add (menu); setJMenuBar (menuBar); // Додавання текстової обасти і комбінованого списку fileText = new JTextArea (); fileCombo = new JComboBox (); fileCombo.addActionListener (new ActionListener () {public void actionPerformed (ActionEvent e) {loadZipFile ((String) fileCombo.getSelectedItem ());}}); add (fileCombo, BorderLayout.SOUTH); add (new JScrollPane (fileText), BorderLayout.CENTER); } / ** * Сканування вмісту ZIP-архіву і заповнення * їм комбінованого списку. * / Public void scanZipFile () {new SwingWorker () {protected Void doInBackground () throws Exception {ZipInputStream zin = new ZipInputStream (new FileInputStream (zipname)); ZipEntry entry; while ((entry = zin.getNextEntry ())! = null) {publish (entry.getName ()); zin.closeEntry (); } Zin.close (); return null; } Protected void process (List names) {for (String name: names) fileCombo.addItem (name); }} .Execute (); } / ** * Завантаження файлу з ZIP-архіву в текстову область * @param name ім'я файлу з архіву * / public void loadZipFile (final String name) {fileCombo.setEnabled (false); fileText.setText ( ""); new SwingWorker () {protected Void doInBackground () throws Exception {try {ZipInputStream zin = new ZipInputStream (new FileInputStream (zipname)); ZipEntry entry; // пошук запису з відповідними ім'ям в архіві while ((entry = zin.getNextEntry ())! = Null) {if (entry.getName (). Equals (name)) {// зчитування запису в текстову область Scanner in = new Scanner (zin); while (in.hasNextLine ()); {FileText.append (in.nextLine ()); fileText.append ( "\ n"); }} Zin.closeEntry (); } Zin.close (); } Catch (IOException e) {e.printStackTrace (); } Return null; } Protected void done () {fileCombo.setEnabled (true); }} .Execute (); } Public static final int DEFAULT_WIDTH = 400; public static final int DEFAULT_HEIGHT = 300; private JComboBox fileCombo; private JTextArea fileText; private String zipname; }