问题描述
我需要根据输入流数据创建一个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,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也总是创建相同的内容,所以我找不到我做错的地方。
要求帮助我找出我做错了什么地方。
解决方法
您消耗了两次相同的输入流:首先阅读它以获得校验和,然后再次阅读以写zip条目。
getCheckSum(in,info.getFileName());
int length;
while ((length = in.read(buffer)) >= 0)
{
zipFileToSend.write(buffer,length);
}
第二次尝试阅读时,不再需要阅读任何内容,因此没有任何内容写入zip条目。
某些输入流可以重置并读取多次,如果不是这种情况,则需要将数据保存到ByteArrayOutputStream
中(就像您在getCheckSum()
方法中所做的那样) ,然后您可以多次读取该数据。