[英]Deflate and Inflate Java String in Memory Zip Exception Error
我正在編寫代碼來壓縮和膨脹 base 64 編碼中的字符串,但出現以下錯誤:
Exception in thread "main" java.util.zip.ZipException: incorrect header check
at java.util.zip.InflaterOutputStream.write(InflaterOutputStream.java:284)
at java.io.FilterOutputStream.write(FilterOutputStream.java:108)
at serializer.test.SerializerTest.main(SerializerTest.java:43)
我的代碼是:
XsltObject Xslt = new XsltObject();
Xslt.setXslt(readFile("C:\\codebase\\OverallSystem\\EBE_TEMPERED_XMLS\\bank_timestamp-0.xml"));
System.out.println("Original String Length: "+ Xslt.getXslt().length());
//JSONObject jsonObj = new JSONObject( Xslt );
// System.out.println( jsonObj );
//System.out.println( "Json Length:" + jsonObj);
DeflaterOutputStream outputStream;
for ( int i = 1; i <= 9; ++i ) {
ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
outputStream = new DeflaterOutputStream(arrayOutputStream, new Deflater( i, true ));
outputStream.write(Xslt.getXslt().getBytes());
outputStream.close();
//System.out.println("Deflate (lvl=" + i + ");" + arrayOutputStream.toString("ISO-8859-1"));
System.out.println("Deflate (lvl=" + i + ");" + arrayOutputStream.toString("ISO-8859-1").length());
String temp = DatatypeConverter.printBase64Binary(arrayOutputStream.toString("UTF-8").getBytes());
System.out.println(temp);
System.out.println("Base 64 len: " + temp.length());
byte[] data =DatatypeConverter.parseBase64Binary(temp);
ByteArrayOutputStream inflateArrayOutputStream = new ByteArrayOutputStream();
InflaterOutputStream iis = new InflaterOutputStream(inflateArrayOutputStream, new Inflater());
iis.write(data);
iis.close();
System.out.println("Inflate (lvl=" + i + ");" + inflateArrayOutputStream.toString("ISO-8859-1"));
System.out.println("Inflate (lvl=" + i + ");" + inflateArrayOutputStream.toString("ISO-8859-1").length());
我究竟做錯了什么?
這解決了我的所有問題,並且是所有 JDK 用法:
package serializer.test;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.zip.*;
import javax.xml.bind.DatatypeConverter;
public class DeflationApp
{
private String compressBase64(String stringToCompress, int level)
throws UnsupportedEncodingException
{
byte[] compressedData = new byte[1024];
byte[] stringAsBytes = stringToCompress.getBytes("UTF-8");
Deflater compressor = new Deflater(level, false);
compressor.setInput(stringAsBytes);
compressor.finish();
int compressedDataLength = compressor.deflate(compressedData);
byte[] bytes = Arrays.copyOf(compressedData, compressedDataLength);
return DatatypeConverter.printBase64Binary(bytes);
}
private String decompressToStringBase64(String base64String)
throws UnsupportedEncodingException, DataFormatException
{
byte[] compressedData = DatatypeConverter
.parseBase64Binary(base64String);
Inflater deCompressor = new Inflater();
deCompressor.setInput(compressedData, 0, compressedData.length);
byte[] output = new byte[100000];
int decompressedDataLength = deCompressor.inflate(output);
deCompressor.end();
return new String(output, 0, decompressedDataLength, "UTF-8");
}
public static void main(String[] args) throws DataFormatException,
IOException
{
DeflationApp m = new DeflationApp();
String strToBeCompressed = readFile(
"C:\\codebase\\OverallSystem\\MappingMapToEBECommon.xslt")
.trim();
for (int i = 1; i <= 9; ++i)
{
String compressedData = m.compressBase64(strToBeCompressed, i);
String deCompressedString = m.decompressToStringBase64(compressedData);
System.out.println("Base 64:");
System.out.println("Original Length with level("+i+"): " + strToBeCompressed.length());
System.out.println("Compressed with level("+i+"): " + compressedData.toString());
System.out.println("Compressed with level("+i+") Length: " + compressedData.toString().length());
System.out.println("Decompressed with level("+i+"): " +
+ deCompressedString.length());
System.out.println("Decompressed with level("+i+"): " + deCompressedString);
}
for (int i = 1; i <= 9; ++i)
{
byte[] compressedData = m.compress(strToBeCompressed, i);
String deCompressedString = m.decompressToString(compressedData);
System.out.println("Without Base 64:");
System.out.println("Original Length with level("+i+"): " + strToBeCompressed.length());
System.out.println("Compressed with level("+i+"): " + new String(compressedData));
System.out.println("Compressed with level("+i+") Length: " + new String(compressedData).length());
System.out.println("Decompressed with level("+i+"): " +
+ deCompressedString.length());
System.out.println("Decompressed with level("+i+"): " + deCompressedString);
}
}
private byte[] compress(String stringToCompress, int level) throws UnsupportedEncodingException
{
byte[] compressedData = new byte[1024];
byte[] stringAsBytes = stringToCompress.getBytes("UTF-8");
Deflater compressor = new Deflater(level, false);
compressor.setInput(stringAsBytes);
compressor.finish();
int compressedDataLength = compressor.deflate(compressedData);
return Arrays.copyOf(compressedData, compressedDataLength);
}
private String decompressToString(byte[] compressedData) throws UnsupportedEncodingException, DataFormatException
{
Inflater deCompressor = new Inflater();
deCompressor.setInput(compressedData, 0, compressedData.length);
byte[] output = new byte[100000];
int decompressedDataLength = deCompressor.inflate(output);
deCompressor.end();
return new String(output, 0, decompressedDataLength, "UTF-8");
}
public static String readFile(String file) throws IOException
{
BufferedReader reader = new BufferedReader(new FileReader(file));
String line = null;
StringBuilder stringBuilder = new StringBuilder();
String ls = System.getProperty("line.separator");
try
{
while ((line = reader.readLine()) != null)
{
stringBuilder.append(line);
stringBuilder.append(ls);
}
return stringBuilder.toString();
}
finally
{
reader.close();
}
}
}
我也遇到了 DeflaterOutputStream 的內存問題——如果你讓它使用默認構造函數,它就可以工作。 這工作正常:
for (Entry<String, String> entry : valueMap.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DeflaterOutputStream dos = new DeflaterOutputStream(baos);
try {
dos.write(value.getBytes());
dos.flush();
dos.close();
}
catch (IOException e) {
throw new RuntimeException(e);
}
byte[] zipData = baos.toByteArray();
zipValueMap.put(key, zipData);
}
但將其更改為:
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Deflater deflater = new Deflater(Deflater.BEST_SPEED);
DeflaterOutputStream dos = new DeflaterOutputStream(baos, deflater);
這讓我在 JVM C 代碼中出現內存泄漏,占用 80g 並導致我的 mint 系統崩潰。 那么為什么默認構造函數會起作用,而當我在其中傳遞我自己的 deflator 時,它卻失敗得如此嚴重:
解碼 DeflaterOutputStream (java 1.8_40) 我在 close 方法中找到了一些特殊的代碼:
public void close() throws IOException {
if (!closed) {
finish();
if (usesDefaultDeflater)
def.end();
out.close();
closed = true;
}
}
我猜他們把它用於解決放氣器的問題。
最好的解決方案是在循環中顯式調用它:
try {
dos.write(value.getBytes());
dos.flush();
dos.close();
deflater.end();
}
並且不再有內存泄漏。 這也是一個糟糕的內存泄漏,因為它來自 C 端,所以它從來沒有拋出 JVM 錯誤,它只是咀嚼了我擁有的所有 40g 內存,然后從交換空間開始。 我不得不 ssh 進入盒子並殺死它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.