从 Java 中的 inputStream 压缩多个对象

moj*_*ojo 3 java zip inputstream

我有一个允许用户选择图像然后下载它们的 web 应用程序。对于单个图像,我使用 HTML5 的锚点下载,效果很好。现在我需要允许他们选择多个图像,并将它们下载为 .zip 文件。我正在使用 api 将每个图像作为 InputStream 并返回 Jersey 响应。

我是压缩的新手,我对 InputStream 的压缩应该如何工作感到有些困惑。

对于单个图像,它的工作原理如下:

try {
    InputStream imageInputStream = ImageStore.getImage(imageId);

    if (imageInputStream == null) {
        XLog.warnf("Unable to find image [%s].", imageId);
        return Response.status(HttpURLConnection.HTTP_GONE).build();
    }

    Response.ResponseBuilder response = Response.ok(imageInputStream);
    response.header("Content-Type", imageType.mimeType());
    response.header("Content-Disposition", "filename=image.jpg");

    return response.build();
}
Run Code Online (Sandbox Code Playgroud)

它并不多,但这是我迄今为止用于多个图像的 java

public Response zipAndDownload(List<UUID> imageIds) {
    try {
        // TODO: instantiate zip file?

        for (UUID imageId : imageIds) {
            InputStream imageInputStream = ImageStore.getImage(imageId);
            // TODO: add image to zip file (ZipEntry?)
        }

        // TODO: return zip file
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)

我就是不知道怎么处理多个InputStreams,看来我不应该有多个,对吧?

Mik*_*e B 5

一个InputStream每图像OK。要压缩文件,您需要为它们创建一个 .zip 文件以供它们使用并获得ZipOutputStream写入它的权限:

File zipFile = new File("/path/to/your/zipFile.zip");
ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipFile)));
Run Code Online (Sandbox Code Playgroud)

对于每个图像,创建一个新的ZipEntry,将其添加到ZipOutputSteam,然后将图像中的字节复制InputStreamZipOutputStream

ZipEntry ze = new ZipEntry("PrettyPicture1.jpg");
zos.putNextEntry(ze);
byte[] bytes = new byte[1024];
int count = imageInputStream.read(bytes);
while (count > -1)
{
    zos.write(bytes, 0, count);
    count = imageInputStream.read(bytes);
}
imageInputStream.close();
zos.closeEntry();
Run Code Online (Sandbox Code Playgroud)

添加所有条目后,关闭ZipOutputStream

zos.close();
Run Code Online (Sandbox Code Playgroud)

现在您zipFile指向一个充满图片的 zip 文件,您可以随心所欲。您可以像使用单个图像一样返回它:

BufferedInputStream zipFileInputStream = new BufferedInputStream(new FileInputStream(zipFile));
Response.ResponseBuilder response = Response.ok(zipFileInputStream);
Run Code Online (Sandbox Code Playgroud)

但是内容类型和配置不同:

response.header("Content-Type", MediaType.APPLICATION_OCTET_STREAM_TYPE);
response.header("Content-Disposition", "attachment; filename=zipFile.zip");
Run Code Online (Sandbox Code Playgroud)

注意:您可以使用Guava 的helper 中copy方法来复制流,而不是手动复制字节。只需用这一行替换循环和它之前的 2 行:ByteStreamswhile

ByteStreams.copy(imageInputStream, zos);
Run Code Online (Sandbox Code Playgroud)