如何使用与.Net兼容的GZIPOutputStream压缩和解压缩字符串?

Bob*_*obs 56 .net compression zip android gzip

我需要一个在android中使用GZip压缩字符串的示例.我想向方法发送一个像"hello"这样的字符串并获得以下压缩字符串:

BQAAAB + LCAAAAAAABADtvQdgHEmWJSYvbcp7f0r1StfgdKEIgGATJNiQQBDswYjN5pLsHWlHIymrKoHKZVZlXWYWQMztnbz33nvvvffee ++ 997o7nU4n99 // P1xmZAFs9s5K2smeIYCqyB8/fnwfPyLmeVlW/W + GphA2BQAAAA ==

然后我需要解压缩它.谁能给我一个例子并完成以下方法?

private String compressString(String input) {
    //...
}

private String decompressString(String input) {
    //...
}
Run Code Online (Sandbox Code Playgroud)

谢谢,


更新

根据scessor的回答,现在我有以下4种方法.Android和.net压缩和解压缩方法.除一种情况外,这些方法彼此兼容.我的意思是它们在前3个状态中兼容但在第4个状态下不兼容:

  • 状态1)Android.compress < - > Android.decompress :( 好的)
  • 状态2)Net.compress < - > Net.decompress :( 好的)
  • 状态3)Net.compress - > Android.decompress :( 好的)
  • 状态4)Android.compress - > .Net.decompress :( 不行)

任何人都可以解决它吗?

Android方法:

public static String compress(String str) throws IOException {

    byte[] blockcopy = ByteBuffer
            .allocate(4)
            .order(java.nio.ByteOrder.LITTLE_ENDIAN)
            .putInt(str.length())
            .array();
    ByteArrayOutputStream os = new ByteArrayOutputStream(str.length());
    GZIPOutputStream gos = new GZIPOutputStream(os);
    gos.write(str.getBytes());
    gos.close();
    os.close();
    byte[] compressed = new byte[4 + os.toByteArray().length];
    System.arraycopy(blockcopy, 0, compressed, 0, 4);
    System.arraycopy(os.toByteArray(), 0, compressed, 4,
            os.toByteArray().length);
    return Base64.encode(compressed);

}

public static String decompress(String zipText) throws IOException {
    byte[] compressed = Base64.decode(zipText);
    if (compressed.length > 4)
    {
        GZIPInputStream gzipInputStream = new GZIPInputStream(
                new ByteArrayInputStream(compressed, 4,
                        compressed.length - 4));

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        for (int value = 0; value != -1;) {
            value = gzipInputStream.read();
            if (value != -1) {
                baos.write(value);
            }
        }
        gzipInputStream.close();
        baos.close();
        String sReturn = new String(baos.toByteArray(), "UTF-8");
        return sReturn;
    }
    else
    {
        return "";
    }
}
Run Code Online (Sandbox Code Playgroud)

.Net方法:

public static string compress(string text)
{
    byte[] buffer = Encoding.UTF8.GetBytes(text);
    MemoryStream ms = new MemoryStream();
    using (GZipStream zip = new GZipStream(ms, CompressionMode.Compress, true))
    {
        zip.Write(buffer, 0, buffer.Length);
    }

    ms.Position = 0;
    MemoryStream outStream = new MemoryStream();

    byte[] compressed = new byte[ms.Length];
    ms.Read(compressed, 0, compressed.Length);

    byte[] gzBuffer = new byte[compressed.Length + 4];
    System.Buffer.BlockCopy(compressed, 0, gzBuffer, 4, compressed.Length);
    System.Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, gzBuffer, 0, 4);
    return Convert.ToBase64String(gzBuffer);
}

public static string decompress(string compressedText)
{
    byte[] gzBuffer = Convert.FromBase64String(compressedText);
    using (MemoryStream ms = new MemoryStream())
    {
        int msgLength = BitConverter.ToInt32(gzBuffer, 0);
        ms.Write(gzBuffer, 4, gzBuffer.Length - 4);

        byte[] buffer = new byte[msgLength];

        ms.Position = 0;
        using (GZipStream zip = new GZipStream(ms, CompressionMode.Decompress))
        {
            zip.Read(buffer, 0, buffer.Length);
        }

        return Encoding.UTF8.GetString(buffer);
    }
}
Run Code Online (Sandbox Code Playgroud)

sce*_*sor 85

GZIP方法:

public static byte[] compress(String string) throws IOException {
    ByteArrayOutputStream os = new ByteArrayOutputStream(string.length());
    GZIPOutputStream gos = new GZIPOutputStream(os);
    gos.write(string.getBytes());
    gos.close();
    byte[] compressed = os.toByteArray();
    os.close();
    return compressed;
}

public static String decompress(byte[] compressed) throws IOException {
    final int BUFFER_SIZE = 32;
    ByteArrayInputStream is = new ByteArrayInputStream(compressed);
    GZIPInputStream gis = new GZIPInputStream(is, BUFFER_SIZE);
    StringBuilder string = new StringBuilder();
    byte[] data = new byte[BUFFER_SIZE];
    int bytesRead;
    while ((bytesRead = gis.read(data)) != -1) {
        string.append(new String(data, 0, bytesRead));
    }
    gis.close();
    is.close();
    return string.toString();
}
Run Code Online (Sandbox Code Playgroud)

并测试:

final String text = "hello";
try {
    byte[] compressed = compress(text);
    for (byte character : compressed) {
        Log.d("test", String.valueOf(character));
    }
    String decompressed = decompress(compressed);
    Log.d("test", decompressed);
} catch (IOException e) {
    e.printStackTrace();
}
Run Code Online (Sandbox Code Playgroud)

===更新===

如果你需要.Net兼容性,我的代码必须改变一点:

public static byte[] compress(String string) throws IOException {
    byte[] blockcopy = ByteBuffer
        .allocate(4)
        .order(java.nio.ByteOrder.LITTLE_ENDIAN)
        .putInt(string.length())
        .array();
    ByteArrayOutputStream os = new ByteArrayOutputStream(string.length());
    GZIPOutputStream gos = new GZIPOutputStream(os);
    gos.write(string.getBytes());
    gos.close();
    os.close();
    byte[] compressed = new byte[4 + os.toByteArray().length];
    System.arraycopy(blockcopy, 0, compressed, 0, 4);
    System.arraycopy(os.toByteArray(), 0, compressed, 4, os.toByteArray().length);
    return compressed;
}

public static String decompress(byte[] compressed) throws IOException {
    final int BUFFER_SIZE = 32;
    ByteArrayInputStream is = new ByteArrayInputStream(compressed, 4, compressed.length - 4);
    GZIPInputStream gis = new GZIPInputStream(is, BUFFER_SIZE);
    StringBuilder string = new StringBuilder();
    byte[] data = new byte[BUFFER_SIZE];
    int bytesRead;
    while ((bytesRead = gis.read(data)) != -1) {
        string.append(new String(data, 0, bytesRead));
    }
    gis.close();
    is.close();
    return string.toString();
}
Run Code Online (Sandbox Code Playgroud)

您可以使用相同的测试脚本.

  • 伙计,我为你摘下帽子!这个站点上很少有人知道单元测试以及为什么要这样做!当之无愧的+1! (2认同)

Mar*_*ler 14

无论是对BQAAAB + LC压缩的"你好"是什么......是一个特别差的gzipper实现.它扩展了"Hello"远远超过必要的范围,使用动态块而不是deflate格式的静态块.删除gzip流的四字节前缀(始终以hex 1f 8b开头)后,"Hello"扩展为123字节.在压缩世界中,这被视为犯罪.

您抱怨的Compress方法正常且正常.它生成一个静态块,总输出为25个字节.gzip格式具有10字节头和8字节尾部开销,使得5字节输入已经被编码为7个字节.这还差不多.

不可压缩的流将被扩展,但它不应该太多.对于不可压缩数据,gzip使用的deflate格式将为每16K到64K增加5个字节.

为了获得实际的压缩,通常你需要为压缩器提供更多的工作来处理这五个字节,这样它就可以在可压缩数据中找到重复的字符串和有偏差的统计数据.我知道你只是用短字符串进行测试.但是在实际应用中,你永远不会使用具有这种短字符串的通用压缩器,因为发送字符串总是更好.