Java.io.IOException:不是GZIP格式

Java.io.IOException:不是GZIP格式,java,gzipinputstream,Java,Gzipinputstream,我搜索了一个如何在Java中压缩字符串的示例 我有一个先压缩再解压缩的函数。压缩似乎很好: public static String encStage1(String str) { String format1 = "ISO-8859-1"; String format2 = "UTF-8"; if (str == null || str.length() == 0) { return str; }

我搜索了一个如何在Java中压缩字符串的示例

我有一个先压缩再解压缩的函数。压缩似乎很好:

   public static String encStage1(String str)
   {
      String format1 = "ISO-8859-1";
      String format2 = "UTF-8";
      if (str == null || str.length() == 0)
      {
         return str;
      }
      System.out.println("String length : " + str.length());
      ByteArrayOutputStream out = new ByteArrayOutputStream();
      String outStr = null;
      try
      {
         GZIPOutputStream gzip = new GZIPOutputStream(out);
         gzip.write(str.getBytes());
         gzip.close();
         outStr = out.toString(format2);
         System.out.println("Output String lenght : " + outStr.length());
      } catch (Exception e)
      {
                  e.printStackTrace();

      }
      return outStr;
   }
但反过来说,即使我将encStage1的返回直接传递回decStage3,字符串也不是GZIP格式:

   public static String decStage3(String str)
   {
      if (str == null || str.length() == 0)
      {
         return str;
      }
      System.out.println("Input String length : " + str.length());
      String outStr = "";
      try
      {
         String format1 = "ISO-8859-1";
         String format2 = "UTF-8";
         GZIPInputStream gis = new GZIPInputStream(new ByteArrayInputStream(str.getBytes(format2)));
         BufferedReader bf = new BufferedReader(new InputStreamReader(gis, format2));
         String line;
         while ((line = bf.readLine()) != null)
         {
            outStr += line;
         }
         System.out.println("Output String lenght : " + outStr.length());
      } catch (Exception e)
      {
         e.printStackTrace();
      }
      return outStr;
   }
当我使用encStage1返回的字符串调用时,会出现此错误:

   public String encIDData(String idData)
   {
      String tst = "A simple test string";
      System.out.println("Enc 0: " + tst);
      String stg1 = encStage1(tst);
      System.out.println("Enc 1: " + toHex(stg1));
      String dec1 = decStage3(stg1);
      System.out.println("unzip: " + toHex(dec1));
   }
输出/错误:

Enc 0: A simple test string
String length : 20
Output String lenght : 40
Enc 1: 1fefbfbd0800000000000000735428efbfbdefbfbd2defbfbd495528492d2e51282e29efbfbdefbfbd4b07005aefbfbd21efbfbd14000000
Input String length : 40
java.io.IOException: Not in GZIP format
    at java.util.zip.GZIPInputStream.readHeader(GZIPInputStream.java:137)
    at java.util.zip.GZIPInputStream.<init>(GZIPInputStream.java:58)
    at java.util.zip.GZIPInputStream.<init>(GZIPInputStream.java:68)
enc0:一个简单的测试字符串
字符串长度:20
输出字符串长度:40
附件1:1EFBFBD080000000000000735428EFBFBDEFBD2DEFBFBD495528492D2E51282E29EFBFBDFBD4B07005AEFBD21EFBD14000000
输入字符串长度:40
java.io.IOException:不是GZIP格式
位于java.util.zip.GZIPInputStream.readHeader(GZIPInputStream.java:137)
位于java.util.zip.GZIPInputStream。(GZIPInputStream.java:58)
位于java.util.zip.GZIPInputStream。(GZIPInputStream.java:68)
一个小错误是:

     gzip.write(str.getBytes());
采用默认的平台编码,在Windows上永远不会是ISO-8859-1。更好:

     gzip.write(str.getBytes(format1));
你可以考虑使用“CP1252”,Windows LATIN-1(一些欧洲语言),而不是“ISO-859-1”,拉丁语-1。加上逗号之类的引号

主要错误是将压缩字节转换为字符串。Java将二进制数据(字节[]、InputStream、OutputStream)从文本(字符串、字符、读取器、写入器)中分离出来,文本在内部始终以Unicode格式保存。字节序列不需要是有效的UTF-8。您可以通过将字节转换为单字节编码(例如ISO-8859-1)来避免这种情况

最好的办法是

     gzip.write(str.getBytes(StandardCharsets.UTF_8));
因此,您拥有完整的Unicode,每个脚本都可以组合

并通过tearrayoutputstream解压为
新字符串(baos.toByteArray(),StandardCharsets.UTF_8)
。 在具有UTF-8的InputStreamReader上使用BufferedReader也可以,但readLine会丢弃换行符

outStr += line + "\r\n"; // Or so.

干净的回答:


使用toString/getBytes进行编码/解码是一种错误的方法。为此,尝试使用类似BASE64的编码(JDK1.8中的java.util.BASE64)

作为证明,请尝试以下简单测试:

import org.testng.annotations.Test;
import java.io.ByteArrayOutputStream;
import static org.testng.Assert.assertEquals;

public class SimpleTest {

    @Test
    public void test() throws Exception {

        final String CS = "utf-8";

        byte[] b0 = {(byte) 0xff};
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        out.write(b0);
        out.close();

        byte[] b1 = out.toString(CS).getBytes(CS);

        assertEquals(b0, b1);
    }
}

编辑:删除我的评论。您不能简单地进行十六进制转换,因为您缺少令牌式十六进制解析afaik。您应该通过在输入字节数组和输出字节数组之间进行字节比较的单元测试来验证字节->十六进制和十六进制->字节转换。
import org.testng.annotations.Test;
import java.io.ByteArrayOutputStream;
import static org.testng.Assert.assertEquals;

public class SimpleTest {

    @Test
    public void test() throws Exception {

        final String CS = "utf-8";

        byte[] b0 = {(byte) 0xff};
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        out.write(b0);
        out.close();

        byte[] b1 = out.toString(CS).getBytes(CS);

        assertEquals(b0, b1);
    }
}