Шаг 104.
Язык программирования Java.
Класс ZipInputStream

На этом шаге мы рассмотрим класс ZipInputStream

Ранее мы приводили пример обхода содержимого архива для получения информации о файлах в данном архиве. Используя этот пример можно написать функцию, которая будет обходить архив и извлекать файлы и папки из этого архива. Для того чтобы полностью извлечь файл, нужно скопировать его содержимое из архива в созданный файл в целевой папке. Для этого используют функцию getInputStream() у объекта типа ZipFile. Она объявлена следующим образом:

public InputStream getInputStream(ZipEntry entry) throws IOException

Данная функция принимает один аргумент типа ZipEntry, то есть тот файл который мы хотим извлечь из архива. Возвращает данная функция входной поток для чтения данных. Данную функцию можно применять только для файлов в архиве. После получения входного потока нужно считать все содержимое из этого потока в файл в целевой папке. Для этого можно использовать функцию write() из предыдущего шага, которую мы применяли для функции архивирования.


Приведем ниже пример программы для разархивирования. Имя архива и путь до целевой папки передаются через аргументы командной строки.

import java.io.*;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

public class Main {
    private static File src;
    private static File dest;

    /**
     * Вспомогательная функция для копирования байтов из одного потока в другой
     * @param in поток ввода
     * @param out поток вывода
     * */
    private static void write(InputStream in, OutputStream out) throws IOException {
        byte[] buffer = new byte[1024];
        while (in.read(buffer) != -1) {
            out.write(buffer);
        }
    }

    /**
     * Функция для разархивирования архива
     * */
    private static void extract() throws IOException {
        /*Создаем ссылку на наш архив*/
        ZipFile zipFile = new ZipFile(src.getPath());
        /*Получаем список его записей*/
        Enumeration entries = zipFile.entries();

        /*Пока мы не просмотрим все записи*/
        while (entries.hasMoreElements()) {
            /*Получим очередную запись*/
            ZipEntry entry = (ZipEntry) entries.nextElement();
            /*Выведем ее имя*/
            System.out.print("name: " + entry.getName());

            /*Если наща запись это файл*/
            if (!entry.isDirectory()) {
                /*
                  то нужно перед распаковкой создать весь путь с учетом путей в архиве
                  (мы должны распаковывать в файл, с тем же путем что в записи).
                  Поэтому нужно создать все папки на пути до корневой папки
                */

                /*создади ссылку на наш будущий файл*/
                File file = new File(entry.getName());

                /*Создадим все несуществующие папки*/
                File dir = new File(dest.getAbsolutePath() + "/" + file.getParent());
                dir.mkdirs();

                /*
                  Скопируем все содержимое из файла в архиве в результирующий файл.
                  Для это воспользуемся функцией getInputStream(entry) 
                                                            и функцией write(in, out).
                */
                File dest = new File(dir, file.getName());
                try (
                        InputStream in = zipFile.getInputStream(entry);
                        OutputStream out = new FileOutputStream(dest)
                ) {
                    write(in, out);
                }

            } else {
                /*Если рассматриваемая запись это папка, то нужно просто создать 
                                                  все папки на пути от этой до корня*/
                File dir = new File(dest.getAbsolutePath() + "/" + entry.getName());
                dir.mkdirs();
            }
            System.out.println(" ------- OK");
        }

        /*После работы с архивом обязательно его закроем*/
        zipFile.close();
    }

    /**
     * Функция для проверки аргументов командной строки
     * @param args аргументы командной строки
     * @return true, если мы корректно передали неообходимые аргументы, 
     *                                                     и false в противном случае
     * */
    private static boolean checkArgs(String[] args) {
        /*Проверяем что программе переданны не пути*/
        if (args.length < 2) {
            System.out.println("Введите путь к архиву и путь для распаковки");
            return false;
        }

        String zipName = args[0];
        src = new File(zipName);
        if (!src.exists()) {
            System.out.println("Заданный архив не существует");
            return false;
        }

        String destName = args[1];
        dest = new File(destName);
        if (!dest.exists()) {
            System.out.println("Задан несуществующий путь для разархивирования");
            return false;
        }

        return true;
    }

    public static void main(String[] args) throws IOException {
        if (checkArgs(args)) {
            System.out.println("start extraction");
            extract();
            System.out.println("end extraction");
        }
    }
}

Проект можно взять здесь


Рис. 1. Вывод программы


На следующем шаге мы начнем рассматривать систему NIO.2

Предыдущий шаг Содержание Следующий шаг