簡體   English   中英

壓縮和膨脹內存 Zip 異常錯誤中的 Java 字符串

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM