Проблема с открытием/загрузкой zip-файла после распаковки (Java/ZipInputStream)

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

Поскольку я не могу отфильтровать некоторую информацию в файле из источника, где файл создается с самого начала, мое решение состоит в том, чтобы распаковать файл, прочитать эти три файла как строки, а затем отфильтровать их. В конце «пересоберите» все как «zip-файл» (inputStream) и верните inputStream.

Проблема
В настоящее время я создал класс для обработки распаковки и фильтрации файла. В конце концов, я просто хочу вернуть новый inputStream, содержащий zip-файл и три файла внутри.

Я дошел до того, что получил контент из объекта HTTP в inputStream, распаковал этот inputStream и получил три файла в виде трех строк. Чтобы просто попытаться проверить, работает ли это, я в настоящее время не хочу делать больше, чем просто распаковывать их, просто закрывать inputStream и возвращать его. Однако это вызывает исключение, когда я возвращаю inputStream:

 java.io.IOException: Attempted read on closed stream.

Это связано с тем, что inputStream используется вне функции, которую я представляю ниже. Когда я закрываю zipInputStream, я, вероятно, также закрываю inputStream для дальнейшей работы.

Текущий код

public InputStream convertInputStream(HttpEntity entity)
{
    InputStream inputStream = null;
    try
    {
        inputStream = entity.getContent();
    }
    catch (IOException e11)
    {

    }

    ZipInputStream zipInputStream = new ZipInputStream(inputStream);
    Vector <String>entryVector = new Vector<String>();
    ZipEntry entry;
    try
    {
        String entryValue;
        while((entry = zipInputStream.getNextEntry()) != null)
        {           
            System.out.println("Unzipping file: " + entry.getName() + "...");
            byte [] buf = new byte[(int) entry.getSize()];
            zipInputStream.read(buf);
            entryValue = new String(buf);
            entryVector.add(entryValue);
            zipInputStream.closeEntry();
        }
    }
    catch(IOException e)
    {
        System.out.println("error in getting next entry.");
    }
    finally
    {
        try 
        {
            zipInputStream.close();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        System.out.println("Unzipping done!");
    }
    return inputStream;
}

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


person user373455    schedule 08.07.2010    source источник
comment
тот же zip-файл пытается скачать, ссылка меняется и я не могу добраться до файла. - можно здесь подробнее?   -  person Mike Tunnicliffe    schedule 08.07.2010
comment
Хм. Сказать, что ссылка меняется, может быть неправдой, но браузер говорит, что файл не может быть найден, значит, каким-то образом имя было повреждено? Моя теория заключается в том, что при закрытии zipInputStream я также закрываю основной поток; inputStream (который используется позже после выполнения этой функции).   -  person user373455    schedule 08.07.2010
comment
Как работает браузер? В вашем примере читается zip-файл, печатается имя файла, а затем закрывается zip-файл. Где появляется браузер?   -  person Thomas Lötzer    schedule 08.07.2010
comment
Да, это не имеет отношения к ошибке, плохое объяснение от меня. При вызове zipInputStream.close() я получаю исключение, которое я обновил выше. edit Я подчистил вопрос. /изменить   -  person user373455    schedule 08.07.2010
comment
Какова цель этого метода?   -  person Mike Tunnicliffe    schedule 08.07.2010
comment
Конечная цель (это только начало урока) состоит в том, чтобы распаковать zip-файл, получить содержимое, изменить что-то в этом файле, а затем снова сжать и перемешать его...   -  person user373455    schedule 08.07.2010
comment
Что еще есть в InputStream? Можете ли вы дать нам больше контекста? Что вы пытаетесь сделать, когда возникает исключение?   -  person Thomas Lötzer    schedule 08.07.2010
comment
Попытался объяснить подробнее.   -  person user373455    schedule 08.07.2010
comment
Хорошо, я понял намного больше. Чего я до сих пор не понимаю, так это того, что вы пытаетесь прочитать из InputStream при возникновении исключения.   -  person Thomas Lötzer    schedule 08.07.2010
comment
Дело в том, что я использую IOUtils.copyLarge(inputStream, outputStream); после изменения inputStream. Я знаю, вижу, я понял это немного неправильно. Я хочу изменить inputStream до того, как это будет сделано, что довольно сложно и, как мне кажется, не так, как эти вещи должны работать. Есть идеи по альтернативному решению?   -  person user373455    schedule 08.07.2010


Ответы (4)


Когда вы печатаете «разархивирующий файл», вы на самом деле ничего не распаковываете. Если вы хотите это сделать, вам нужно прочитать содержимое записи из ZipInputStream с помощью функции read() и записать его в файл.

EDIT: вы можете попробовать прочитать (сжатый) zip-файл из входного потока в массив байтов. Затем создайте ByteArrayInputStream в этом массиве, а затем оберните вокруг него ZipInputStream. Затем вы можете безопасно закрыть входной поток, не закрывая базовый поток.

Кроме того, убедитесь, что содержимое файла в виде строки действительно полезно. new String(byte[]) создает строку, используя кодировку по умолчанию, так что это вполне может быть бесполезно.

person Thomas Lötzer    schedule 08.07.2010
comment
Хм, конечно, я пропустил эту деталь :P. Но это не должно повредить исходный zip-файл? - person user373455; 08.07.2010
comment
Нет, не должен, так как файл не изменен. - person Thomas Lötzer; 08.07.2010
comment
Хм. Хорошо. Моя проблема в том, что у меня есть поток ввода, где я хочу изменить содержимое некоторых файлов внутри zip-файла. После этого я хочу снова сжать его и снова использовать все как входной поток, что кажется довольно странным, поскольку вы обычно используете этот вид техники... Мне это нужно как входной поток из-за использования функции IOUtils.copyLarge(inputStream, выходной поток); Таким образом, возвращаемое значение после изменения содержимого и сжатия должно быть входным потоком... - person user373455; 08.07.2010
comment
Но этот входной поток не имеет ничего общего с входным потоком, который вы получаете. Вам нужно вернуть новый входной поток чтения из вашего модифицированного zip-файла. - person Thomas Lötzer; 08.07.2010
comment
Да, это я тоже успел понять. Проблема, которую я вижу, заключается в том, чтобы получить новый поток ввода... Пока мне удалось получить ByteArrayInputStream :), - person user373455; 08.07.2010

То есть вы не "качаете" по сети? Под загрузкой вы подразумеваете распаковку файлов из zip-архива на локальный жесткий диск?

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

    private static File unZipFile(File zipFileIn) throws Exception {
        ZipFile unZipFile = new ZipFile(zipFileIn);
        Enumeration<? extends ZipEntry> entries = unZipFile.entries();
        String topFile = null;
        while (entries.hasMoreElements()) {
            ZipEntry entry = (ZipEntry) entries.nextElement();
                if (entry.isDirectory()) {
                // Assume directories are stored parents first then children
                String extractFile = entry.getName();
                if (topFile == null) {
                    topFile = extractFile;
                }
                // This is not robust, just a quick solution
                (new File(entry.getName())).mkdir();
                continue;
            }
            copyInputStream(unZipFile.getInputStream(entry),new BufferedOutp    utStream(new FileOutputStream(entry.getName())));
        }
        unZipFile.close();
        File newFile = new File(zipFileIn.getParentFile().getAbsoluteFile(),topFile);
        return newFile;
    }

    private static final void copyInputStream(InputStream in, OutputStream out) throws IOException {
        byte[] buffer = new byte[1024];
        int len;
            while((len = in.read(buffer)) >= 0)
            out.write(buffer, 0, len);
            in.close();
        out.close();
    }

Метод возвращает вам файл, который является корнем распакованных файлов.

Возможно, было бы неплохо более подробно задать вопрос о том, что вы пытаетесь сделать. ATM все угадывают, что вы пытаетесь сделать, вместо того, чтобы работать над решением.

person Erik    schedule 08.07.2010
comment
Спасибо большое. Я обновлю свой вопрос через мгновение, чтобы попытаться объяснить цель всего этого. - person user373455; 08.07.2010

Я думаю, что вам нужно прочитать содержимое каждой записи, а затем вызвать entry.closeEntry()

person Maurice Perry    schedule 08.07.2010
comment
да. Код теперь обновлен, выдает исключение при попытке закрыть zipInputStream. Если нет, то zip-файл поврежден. - person user373455; 08.07.2010

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

Если вам не нужны оба, вы можете выбрать, какой из них вы хотите сделать, либо записав простой поток на диск, чтобы получить двоичный zip-файл (нет необходимости использовать ZipInputStream); или используя ZipInputStream и считывая данные из каждой записи и записывая их на диск (но не используйте простой входной поток для записи на диск).

person Mike Tunnicliffe    schedule 08.07.2010