首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何使用与.Net兼容的GZIPOutputStream对字符串进行压缩和解压缩?

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

Stack Overflow用户
提问于 2011-07-16 19:54:57
回答 9查看 64.1K关注 0票数 58

我需要一个在安卓系统中使用GZip压缩字符串的例子。我想向该方法发送一个类似"hello“的字符串,并获得以下压缩字符串:

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

然后我需要解压它。谁能给我举个例子,完成下面的方法?

代码语言:javascript
运行
复制
private String compressString(String input) {
    //...
}

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

谢谢,

更新

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

非状态状态1) (OK)

  • state <-> Android.decompress:(OK)

  • state 2) Net.compress <-> Net.decompress: OK)

3)

  • Net.compress -> Android.decompress:(OK)

  • state 4) Android.compress -> .Net.decompress:(NOT state

有人能解决这个问题吗?

安卓方法:

代码语言:javascript
运行
复制
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 "";
    }
}

.Net方法:

代码语言:javascript
运行
复制
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);
    }
}
EN

回答 9

Stack Overflow用户

回答已采纳

发布于 2011-07-17 00:26:17

GZIP方法:

代码语言:javascript
运行
复制
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();
}

还有一个测试:

代码语言:javascript
运行
复制
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();
}

===更新===

如果你需要.Net兼容性,我的代码必须稍微修改一下:

代码语言:javascript
运行
复制
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();
}

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

票数 94
EN

Stack Overflow用户

发布于 2012-03-28 12:23:56

不管对BQAAAB+LC压缩的“你好”是什么..。是gzipper的一个特别糟糕的实现。它使用动态块而不是deflate格式的静态块扩展了"Hello“,远远超出了必要的程度。在删除gzip流的4字节前缀(始终以十六进制1f 8b开头)之后,"Hello“被扩展到123字节。在压缩领域,这被认为是一种犯罪。

您抱怨的Compress方法工作正常。它正在生成一个静态块和25字节的总输出。gzip格式具有10个字节的头部和8个字节的尾部开销,使得5个字节的输入被编码为7个字节。那才像话。

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

要获得实际的压缩效果,通常需要给压缩器更多的空间来处理这5个字节,这样它就可以在可压缩数据中找到重复的字符串和有偏差的统计数据。我知道你只是在用一个短字符串做测试。但在实际应用程序中,您永远不会使用具有如此短字符串的通用压缩器,因为只发送字符串总是更好。

票数 15
EN

Stack Overflow用户

发布于 2012-11-16 21:49:54

我在我的项目中尝试了你的代码,在Android上的压缩方法中发现了一个编码错误:

代码语言:javascript
运行
复制
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());

在上面的代码中,您应该使用正确的编码,并填充字节长度,而不是字符串长度:

代码语言:javascript
运行
复制
byte[] data = str.getBytes("UTF-8");

byte[] blockcopy = ByteBuffer
        .allocate(4)
        .order(java.nio.ByteOrder.LITTLE_ENDIAN)
        .putInt(data.length)
            .array();

ByteArrayOutputStream os = new ByteArrayOutputStream( data.length );    
GZIPOutputStream gos = new GZIPOutputStream(os);
gos.write( data );
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6717165

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档