【问题标题】:Deflate and Inflate Java String in Memory Zip Exception Error内存 Zip 异常错误中的 Deflate 和 Inflate Java 字符串
【发布时间】:2016-07-18 16:25:32
【问题描述】:

我正在编写代码以对 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()); 

我做错了什么?

【问题讨论】:

    标签: java zip deflate inflate


    【解决方案1】:

    这解决了我所有的问题,并且是所有 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();
            }
        }
    
    }
    

    【讨论】:

      【解决方案2】:

      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 内存都吃光了,然后在交换空间上开始。我不得不进入盒子并杀死它。

      【讨论】:

        猜你喜欢
        • 2017-11-17
        • 1970-01-01
        • 2013-10-12
        • 2011-09-04
        • 1970-01-01
        • 1970-01-01
        • 2012-10-03
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多