如何在Java中压缩string?

我使用GZIPOutputStreamZIPOutputStream压缩一个string(我的stringZIPOutputStream string.length()小于20),但压缩的结果比原始string更长。

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

所以,有人可以帮我压缩一个string?

我的function是这样的:

 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)); } } 

结果是:

替代文字

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

压缩只有20个字符的string并不是太容易,并不总是可能的。 如果你有重复,哈夫曼编码或简单的游程编码可能能够压缩,但可能不是非常多。

当你创build一个string时,你可以把它看作是一个char列表,​​这意味着对于你的string中的每个字符,你需要支持所有可能的char值。 从太阳文件

char :char数据types是一个单一的16位Unicode字符。 它具有最小值“\ u0000”(或0)和最大值“\ uffff”(或65,535)。

如果您想要支持的字符集减less,可以编写一个简单的压缩algorithm,类似于binary-> decimal-> hex基数对话。 你从65,536(或者你的目标系统支持的许多字符)到26(按字母)/ 36(字母数字)等等。

我已经使用了这个技巧几次,例如将时间戳编码为文本(target 36 +,source 10) – 只要确保你有足够的unit testing!

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

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

你的朋友是对的。 gzip和ZIP都是基于DEFLATE的 。 这是一个通用的algorithm,不适用于编码小string。

如果你需要这个,一个可能的解决scheme是自定义编码和解码HashMap<String, String> 。 这可以让你做一个简单的一对一的映射:

 HashMap<String, String> toCompressed, toUncompressed; String compressed = toCompressed.get(uncompressed); // ... String uncompressed = toUncompressed.get(compressed); 

显然,这需要设置,而且只适用于less量的string。

霍夫曼编码可能会帮助,但只有当你的小string中有很多频繁的字符

ZIPalgorithm是LZW和霍夫曼树的组合。 您可以单独使用这些algorithm之一。

压缩是基于2个因素:

  • 在您的原始链(LZW)中重复的子串:如果有很多重复,压缩将是有效的。 这个algorithm对压缩长文本文件有很好的效果,因为文字经常重复
  • 压缩链(Huffman)中每个字符的数量:字符之间的重新分配越不平衡,压缩效率越高

在你的情况下,你应该只尝试LZWalgorithm。 基本上使用,可以在不添加元信息的情况下压缩链:对于短string压缩可能更好。

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

霍夫曼编码在这里是一个明智的select。 Gzip和朋友们都这样做,但是他们的工作方式是为inputbuild立霍夫曼树,发送它,然后发送用树编码的数据。 如果树相对于数据较大,则可能没有保存大小。

但是,可以避免发送一个树:相反,你安排发送者和接收者已经有一个。 不能为每个string专门构build,但是可以使用一个全局树来编码所有string。 如果你使用与inputstring相同的语言(英文或其他)build立它,你仍然应该得到很好的压缩效果,尽pipe不如每个input都使用自定义树。

如果你知道你的string大部分是ASCII,你可以将它们转换为UTF-8。

 byte[] bytes = string.getBytes("UTF-8"); 

这可能会减less约50%的内存大小。 但是,你会得到一个字节数组,而不是一个string。 如果你正在写一个文件,那应该不是问题。

要转换回一个string:

 private final Charset UTF8_CHARSET = Charset.forName("UTF-8"); ... String s = new String(bytes, UTF8_CHARSET); 

你没有看到任何压缩发生在你的string上,因为你至less需要几百个字节才能使用GZIPOutputStream或ZIPOutputStream进行真正的压缩。 你的string太小(我不明白为什么你需要压缩)

从这篇文章检查结论:

本文还介绍了如何即时压缩和解压缩数据,以减lessnetworkingstream量并提高客户端/服务器应用程序的性能。 但是,即时压缩数据只有在被压缩的对象超过几百个字节时才提高客户端/服务器应用程序的性能。 例如,如果被压缩和传输的对象是简单的String对象,那么您将无法观察到性能的提高。

看看霍夫曼algorithm。

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

这个想法是,每个字符被replace为位序列,这取决于它们在文本中的频率(频率越高,序列越小)。

你可以阅读你的整个文本,并build立一个代码表,例如:

符号代码

一个0

10

e 110

111

该algorithm基于文本input来构build符号树。 你拥有的angular色越多,压缩的效果就越差。

但取决于你的文字,这可能是有效的。