如何在Java中压缩String?

时间:2010-09-06 06:40:09

标签: java string compression zip

我使用GZIPOutputStreamZIPOutputStream来压缩字符串(我的string.length()小于20),但压缩结果比原始字符串长。

在某些网站上,我发现有些朋友说这是因为我的原始字符串太短,GZIPOutputStream可以用来压缩更长的字符串。

那么,有人可以帮我压缩一个字符串吗?

我的功能如下:

String compress(String original) throws Exception {

}

更新

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.GZIPOutputStream;
import java.util.zip.*;


//ZipUtil 
public class ZipUtil {
    public static String compress(String str) {
        if (str == null || str.length() == 0) {
            return str;
        }

        ByteArrayOutputStream out = new ByteArrayOutputStream();
        GZIPOutputStream gzip = new GZIPOutputStream(out);
        gzip.write(str.getBytes());
        gzip.close();
        return out.toString("ISO-8859-1");
    }

    public static void main(String[] args) throws IOException {
        String string = "admin";
        System.out.println("after compress:");
        System.out.println(ZipUtil.compress(string));
    }
}

结果是:

alt text

10 个答案:

答案 0 :(得分:37)

压缩算法几乎总是有某种形式的空间开销,这意味着它们只在压缩数据时才有效,这些数据足够大,开销小于节省的空间量。

压缩长度仅为20个字符的字符串并不容易,并不总是可行。如果你有重复,霍夫曼编码或简单的游程编码可能能够压缩,但可能不是很多。

答案 1 :(得分:9)

创建String时,可以将其视为char的列表,这意味着对于String中的每个字符,您需要支持char的所有可能值。来自太阳docs

char :char数据类型是一个16位Unicode字符。它的最小值为'\ u0000'(或0),最大值为'\ uffff'(或65,535(含))。

如果你想支持一组缩减的字符,你可以编写一个简单的压缩算法,类似于二进制 - >十进制 - >十六进制基数转换。您从65,536(或目标系统支持的多个字符)到26(字母)/ 36(字母数字)等。

我曾经多次使用过这个技巧,比如将时间戳编码为文本(目标36 +,源码10) - 只要确保你有足够的单元测试!

答案 2 :(得分:7)

如果密码或多或少是“随机”的,那么你运气不好,就无法大幅减少尺寸。

但是:为什么需要压缩密码?也许你需要的不是压缩,而是某种哈希值?如果您只需要检查名称是否与给定密码匹配,则不需要保存密码,但可以保存密码的哈希值。要检查键入的密码是否与给定名称匹配,您可以采用相同的方式构建哈希值,并将其与保存的哈希值进行比较。由于散列(Object.hashCode())是一个int,您将能够以80个字节存储所有20个密码哈希值。

答案 3 :(得分:6)

你的朋友是对的。 gzip和ZIP都基于DEFLATE。这是一种通用算法,不适用于编码小字符串。

如果您需要,可能的解决方案是自定义编码和解码HashMap<String, String>。这可以让您进行简单的一对一映射:

HashMap<String, String> toCompressed, toUncompressed;

String compressed = toCompressed.get(uncompressed);
// ...
String uncompressed = toUncompressed.get(compressed);

显然,这需要设置,并且仅适用于少量字符串。

答案 4 :(得分:4)

Huffman Coding可能会有所帮助,但前提是你的小字符串中有很多频繁的字符

答案 5 :(得分:4)

ZIP算法是LZWHuffman Trees的组合。您可以单独使用这些算法之一。

压缩基于2个因素:

  • 原始链中重复的子串(LZW):如果有很多重复,压缩效率会很高。该算法具有良好的压缩长文本的性能,因为单词经常重复
  • 压缩链中每个字符的数量(Huffman):字符之间的重新分区越多,压缩就越有效率

在您的情况下,您应该只尝试LZW算法。基本上使用,链可以在不添加元信息的情况下进行压缩:对于短字符串压缩可能更好。

对于霍夫曼算法,编码树必须与压缩文本一起发送。因此,对于小文本,由于树,结果可能比原始文本大。

答案 6 :(得分:4)

霍夫曼编码是一个明智的选择。 Gzip和朋友这样做,但他们的工作方式是为输入构建一个Huffman树,发送它,然后发送用树编码的数据。如果树相对于数据较大,则可能没有节省大小。

但是,可以避免发送树:相反,您安排发送方和接收方已经拥有树。它不能专门为每个字符串构建,但您可以使用一个全局树来编码所有字符串。如果你使用与输入字符串(英语或其他)相同的语言构建它,你仍然应该得到良好的压缩,尽管不如每个输入的自定义树一样好。

答案 7 :(得分:0)

您没有看到您的String发生任何压缩,因为您至少需要几百个字节才能使用GZIPOutputStream或ZIPOutputStream进行实际压缩。你的字符串太小了。(我不明白为什么你需要压缩)

检查此article的结论:

  

文章还介绍了如何压缩   并在运行中解压缩数据   为了减少网络流量和   提高你的表现   客户/服务器应用程序   然而,动态压缩数据,   提高了性能   客户端/服务器应用程序仅在   被压缩的对象更多   超过几百个字节。您   无法观察到   如果改善性能   被压缩的对象和   转移是简单的String对象,   例如。

答案 8 :(得分:0)

看看霍夫曼算法。

https://codereview.stackexchange.com/questions/44473/huffman-code-implementation

这个想法是每个字符都被比特序列替换,这取决于它们在文本中的频率(频率越高,序列越小)。

您可以阅读整篇文章并构建代码表,例如:

符号代码

a 0

s 10

e 110

m 111

算法根据文本输入构建符号树。你拥有的角色种类越多,压缩效果就越差。

但根据你的文字,它可能是有效的。

答案 9 :(得分:0)

在Java 9 https://openjdk.java.net/jeps/254中开箱即用提供紧凑的字符串增强功能

java.lang.String现在具有:

  

私有最后一个字节[]值;