在JAVA中实现PHP的gzuncompress
背景
在系统改造的时候,从php迁移到java;由于php中为了节省redis的内存,对缓存的数据做了 gzcompress
处理;为了能读取出数据,有两套方案:
- 刷数据,将redis中老的数据清理掉,去掉
gzcompress
的步骤(缺点:刷数据的时间,和读取代码上线的时间点无法吻合;数据的写入入口比较多,容易遗漏) - java中读取的时候可以进行
gzuncompress
一些知识
知道这些知识候就能避免我在实现过程中遇到的很多问题。
PHP中的 gzcompress
This function compresses the given string using the ZLIB data format.
Note:
This is not the same as gzip compression, which includes some header data. See gzencode() for gzip compression.
一直以为 gzcompress
就是 gz 的压缩,php中使用的 zlib 来压缩,压缩完的结果中携带了头信息,直接使用 gz 解压是不认这种格式的。
JAVA中的 new String(byte[])
java.lang.StringCoding.StringDecoder
当在编码 byte[]
不能处理的时候会进行一些处理;所以说 (new String(compressedByte)).getBytes()
和 compressedByte
并不一定会完全一样。
说到这里就可以看下 jedis 提供的接口了,刚开始我是使用的 String get(String key)
,于是由于上面的原因,当我用这个返回值 getBytes()
的时候就已经发生了变化。正确的使用方法应该是使用 byte[] get(byte[] key)
,由于比较繁琐,封装一下。
实现
public static String get(Jedis jedis, String key) {
byte[] byteKey = key.getBytes();
byte[] element = jedis.get(byteKey);
return new String(gzuncompress(element));
}
public static List<String> mget(Jedis jedis, List<String> keys) {
byte[][] byteKeys = new byte[keys.size()][];
for (int i = 0; i < keys.size(); i++) {
byteKeys[i] = keys.get(i).getBytes();
}
List<byte[]> elements = jedis.mget(byteKeys);
List<String> result = new ArrayList<>();
for (byte[] element : elements) {
result.add(new String(gzuncompress(element)));
}
return result;
}
public static byte[] gzuncompress(byte[] data) {
byte[] unCompressed = null;
ByteArrayOutputStream bos = new ByteArrayOutputStream(data.length);
Inflater deCompressor = new Inflater();
try {
deCompressor.setInput(data);
final byte[] buf = new byte[1024];
while (!deCompressor.finished()) {
int count = deCompressor.inflate(buf);
bos.write(buf, 0, count);
}
unCompressed = bos.toByteArray();
bos.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
deCompressor.end();
}
return unCompressed;
}