Вернуть Zip-файл из ZipOutputStream в Java

У меня есть функция, которая создает Zip-файл из списка файлов. Можно ли вернуть Zip-файл без его сохранения на диск? Мне нужен файл, так как я должен использовать zip-файл в качестве параметра для другой функции. Я не уверен, что ByteStream подойдет мне.

public File compressFileList(List<File> fileList,String fileName) {
    FileOutputStream fileOutputStream=null;
    ZipOutputStream zipOutputStream=null;
    FileInputStream fileInputStream=null;
    String compressedFileName=fileName +".zip";
    if(fileList.isEmpty())
        return null;
    try
    {
        fileOutputStream =  new FileOutputStream(compressedFileName);
        zipOutputStream = new ZipOutputStream(new BufferedOutputStream(fileOutputStream));
        for (File file: fileList) {
            fileInputStream = new FileInputStream(file);
            ZipEntry zipEntry =  new ZipEntry(file.getName());
            zipOutputStream.putNextEntry(zipEntry);
            byte[] tmp = new byte[4*1024];
            int size = 0;
            while((size = fileInputStream.read(tmp)) != -1){
                zipOutputStream.write(tmp, 0, size);
            }
            zipOutputStream.flush();
            fileInputStream.close();
        }
        zipOutputStream.close();
        return compressedFile; //This is what I am missing

    }
    catch (FileNotFoundException e)
    {

    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}

EDIT: добавление варианта использования

Идея состоит в том, чтобы создать ZIP-файл и использовать метод CreateClassifierOptions службы визуального распознавания Watson.

classifierOptions = new CreateClassifierOptions.Builder()
            .classifierName("Santa")
            .addClass("Santa", new File("C:\\app\\GitRepo\\images\\beagle.zip"))
            .negativeExamples(new File("C:\\app\\GitRepo\\images\\nosport.zip"))
            .build();

Построитель принимает zip-файл в качестве параметра.

Понимание

Основываясь на объяснении Александра Дюприе, я думаю, что лучше хранить файл в каком-то месте на жестком диске.


person Vini    schedule 13.11.2017    source источник
comment
что другая функция принимает в качестве входных данных? Inputstream?   -  person Lino    schedule 13.11.2017
comment
Я использую WatsonService API, который принимает на вход zip-файл. или, может быть, я должен создать временный zip-файл и вернуть его функции   -  person Vini    schedule 13.11.2017
comment
Ваш вопрос противоречит вашей подписи метода. Объект File в основном является ссылкой на файл, хранящийся по некоторому пути, но ваш вопрос, похоже, касается возврата (байтового) содержимого файла. Поэтому, если вы не хотите где-то хранить свой файл, вам не следует возвращать объект File.   -  person Rob Obdeijn    schedule 13.11.2017
comment
Должен ли я создать временный файл на диске и отправить его в работу?   -  person Vini    schedule 13.11.2017
comment
Чего вы пытаетесь достичь с функциональной точки зрения? Сохранение временного файла и возврат ссылки на него — вариант, но он зависит от того, что вы хотите делать с этим файлом.   -  person Rob Obdeijn    schedule 13.11.2017
comment
Я хочу использовать Watson Visual API. Visual API использует ZIP-файл в качестве аргумента. Я решил сохранить файл во временной папке и использовать его для вызова Visual API.   -  person Vini    schedule 13.11.2017


Ответы (2)


Вы должны иметь возможность использовать ByteArrayOutputStream вместо FileOutputStream:

zipOutputStream = new ZipOutputStream(new ByteArrayOutputStream());

Трудность здесь заключается в том, чтобы предоставить File методу, использующему zip-файл. java.io.File не предоставляет абстракции, которая позволяет вам манипулировать файлами в памяти.

Абстракция java.io.File и реализация java.io.FileInputStream

Для упрощения, если бы нам пришлось свести к минимуму, что такое абстракция File, мы бы увидели ее как URI. И поэтому, чтобы иметь возможность построить File в памяти или, по крайней мере, имитировать его, нам нужно предоставить URI, который затем будет использоваться потребителем File для чтения его содержимого.

Если мы посмотрим на FileInputStream, который, скорее всего, будет использовать потребитель, мы увидим, что он всегда заканчивается нативным вызовом, который дает нам возможность абстрагировать FileSystem для файлов в памяти:

// class java.io.FileInputStream
/**
 * Opens the specified file for reading.
 * @param name the name of the file
 */
private native void open0(String name) throws FileNotFoundException;

Было бы проще, если бы была возможность адаптировать потребителя к приему InputStream, но, судя по постановке проблемы, я предполагаю, что это невозможно.

Вызов API

Вам необходимо предоставить File для Watson Visual API. Не могли бы вы предоставить метод API, который вам нужно вызвать?

person Alexandre Dupriez    schedule 13.11.2017
comment
Я упомянул, что хочу, чтобы вышеуказанная функция возвращала файл. Вызывающая функция принимает на вход только Zip-файл. - person Vini; 13.11.2017
comment
Да, пожалуйста - интересно, что можно сделать и есть ли обходной путь - person Alexandre Dupriez; 13.11.2017
comment
Я добавил вариант использования. Я предполагаю, что лучше сохранить файл, а затем вызвать службу watson. - person Vini; 13.11.2017

public void compressFileList(List<File> fileList, OutputStream outputStream)
        throws IOException {
    try (ZipOutputStream zipOutputStream =
            new ZipOutputStream(new BufferedOutputStream(outputStream));
        for (File file: fileList) {
            try (FileInputStream fileInputStream = new FileInputStream(file)) {
                ZipEntry zipEntry = new ZipEntry(file.getName());
                zipOutputStream.putNextEntry(zipEntry);
                byte[] tmp = new byte[4*1024];
                int size = 0;
                while((size = fileInputStream.read(tmp)) != -1){
                    zipOutputStream.write(tmp, 0, size);
                }
                zipOutputStream.flush();
            } catch (FileNotFoundException e) { // Maybe skip not found files.
                Logger.log(Level.INFO, "File not found {}", file.getPath());
            }
        }
    }
}

Использование:

if (fileList.isEmpty()) {
    ...
    return;
}
try {
    compressFileList(fileList, servletRequest.getOutputStream())) {
} catch (FileNotFoundException e) {
   ...
} catch (IOException e) {
    ...
}
person Joop Eggen    schedule 13.11.2017
comment
Он не возвращает файл. Я ищу возможность вернуть zip-файл. Я понял, что мне придется временно сохранить файл, прежде чем я смогу использовать его для следующей функции. - person Vini; 13.11.2017
comment
Или (как в моем ответе) вы можете передать OutputStream для доставки zip-файла. Тогда вам не нужно поддерживать массив байтов с содержимым zip-файлов. - person Joop Eggen; 13.11.2017