【问题标题】:Unable to create zip file from InputStream无法从 InputStream 创建 zip 文件
【发布时间】:2020-09-10 16:16:42
【问题描述】:

我需要从输入流数据创建一个 zip 文件,在写入 zip 之前,我需要找到输入流的校验和。

为此,我使用以下代码:

private String writeZipFileToFS(List<ResponsePacks> attachmentList) throws IOException
    {
        File fileToWrite = new File(getZipPath() + "fileName.zip");
        try
        {
            FileUtils.copyInputStreamToFile(compress(attachmentList), fileToWrite);
        }
        catch (IOException e)
        {
            throw e;
        }
        return fileName;
    }

private InputStream compress(List<ResponsePacks> attachmentList)
    {
        byte buffer[] = new byte[2048];
        ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
        ZipOutputStream zipFileToSend = new ZipOutputStream(byteStream);
        try
        {
            for (ResponsePacks info : attachmentList)
            {
                // only for successful requests files would need to be added
                zipFileToSend.putNextEntry(new ZipEntry(info.getFileName()));
                InputStream in = info.getFileContentStream();
                getCheckSum(in, info.getFileName());
                int length;
                while ((length = in.read(buffer)) >= 0)
                {
                    zipFileToSend.write(buffer, 0, length);
                }
                zipFileToSend.closeEntry();
            }
            zipFileToSend.close();
        }
        catch (IOException e)
        {
            throw e;
        }
        return new ByteArrayInputStream(byteStream.toByteArray());
    }
    
    private static void getCheckSum(InputStream is, String fileName)
    {
        byte[] dataCopy = null;
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        try
        {
            IOUtils.copy(is, outputStream);
            dataCopy = outputStream.toByteArray();
            printLog("Byte Array Size {}", dataCopy.length);
            String checkSum = calculateChecksum(dataCopy);
            printLog("Checksum for file {} {}", fileName, checkSum);
            outputStream.flush();
            outputStream.close();
        }
        catch (Exception e)
        {
            printLog("Error on calculationg checksum {}", e.getMessage());
        }
    }

    private static String calculateChecksum(byte[] dataCopy)
    {
        try (ZipInputStream zipInputStream = new ZipInputStream(new ByteArrayInputStream(dataCopy)))
        {
            ZipEntry zipEntry;
            MessageDigest digest = DigestUtils.getSha256Digest();
            DWriter writer = new DWriter(digest);
            while ((zipEntry = zipInputStream.getNextEntry()) != null)
            {
                byte[] entityData = IOUtils.toByteArray(zipInputStream);
                if (!zipEntry.isDirectory())
                {
                    writer.write(entityData);
                }
            }
            if (writer.getChecksum() != null)
            {
                return writer.getChecksum();
            }
        }
        catch (Exception e)
        {
             throw e;
        }
        return "";
    }

static class DWriter
    {
        private final MessageDigest myDigest;

        DWriter(MessageDigest digest)
        {
            myDigest = digest;
        }

        public void write(byte[] data)
        {
            myDigest.update(data);
        }

        public String getChecksum()
        {
            return new String(Hex.encodeHex(myDigest.digest()));
        }
    }

但问题是,如果我要添加代码来计算校验和,然后使用空内容创建 zip 文件,如果我要删除校验和计算代码,然后使用适当的内容创建 zip 文件。

当我检查日志时,我发现 InputStream 内容不同,但我仍然得到相同的 checkSum(空字符串),如下所示:

Byte Array Size 20854
Checksum for file 20200910173919142.json e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
Byte Array Size 14383
Checksum for file 1599752440405.zip e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

我无法找到我做错的地方,因为创建的 zip 文件包含空内容,并且 checkSum 也总是创建相同的内容。

请求帮助我找出我做错的地方。

【问题讨论】:

  • 您正在吞下任何 IOExceptions 并且只是继续进行,就好像它们没有发生一样,这很可能与此有关。 (calculateChecksum 同上)。吞下异常而不记录它们几乎总是是个坏主意。我建议你第一步停止这样做,看看它是否有帮助。
  • 那个特定的校验和值是空字符串的 SHA-256 哈希值,见crypto.stackexchange.com/questions/26133/…

标签: java inputstream checksum outputstream


【解决方案1】:

您使用两次相同的输入流:首先读取它以获取校验和,然后再次读取它以写入 zip 条目。

            getCheckSum(in, info.getFileName());
            int length;
            while ((length = in.read(buffer)) >= 0)
            {
                zipFileToSend.write(buffer, 0, length);
            }

您第二次尝试阅读时,没有任何内容可阅读,因此没有任何内容被写入 zip 条目。

某些输入流可以被重置和多次读取,如果不是这种情况,您需要将数据保存到 ByteArrayOutputStream 中(正如您已经在 getCheckSum() 方法中所做的那样),然后您可以多次读取该数据。

【讨论】:

  • 另外,也许你可以改变你的设计,使校验和计算是一个流处理函数,所以它消耗流,然后进行计算,同时产生一个不变的流,这将成为下一阶段的输入。如果当前架构是流处理管道,这可能是有道理的。
  • 同意,这样会更好
  • @Guillaume 我修改了我的设计,而不是读取两次相同的输入流,我正在读取一次并且在同一个循环中我正在计算校验和,这样就解决了我的第一个问题,即现在 zip 正在正确创建内容,但我仍然无法解决我的第二个问题,即校验和总是为空字符串创建,请检查stackoverflow.com/questions/63844640/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多