在研究以GZIP格式压缩数据后进行redis存取操作以优化性能时遇到了这个问题
数据压缩为GZIP格式后是byte数组的形式,而在使用GZIP进行压缩,创建GZIPOutputStream对象时,会调用一个writeHeader方法,此方法会在输出流中写入GZIP的头信息。
头部信息的前两个字节存储的是标识数据,如果这两个数据出了问题那就无法识别数据格式,就会出现 java.util.zip.ZipException: Not in GZIP format的错误
一开始使用的是项目中自带的redis工具类,使用RedisTemplate进行存储
/**
* 普通缓存获取
*
* @param key 键
* @return 值
*/publicObjectget(String key){return key==null?null: redisTemplate.opsForValue().get(key);}/**
* 普通缓存放入
*
* @param key 键
* @param value 值
* @return true成功 false失败
*/publicbooleanset(String key,Object value){try{
redisTemplate.opsForValue().set(key, value);returntrue;}catch(Exception e){
e.printStackTrace();returnfalse;}}
以这种方式进行存储,在取出时都是以object的形式取出的,而我们需要取出的是byte数组,所以我在取出后先将其转为String类型后再转为字节数组。
但是在这个过程中破坏了GZIP数据的头部信息,使得无法对数据进行解压并报错。
所以为了省去转类型这个步骤以避免头部信息的损坏,因此使用了Jedis 进行存储,使得取出的数据之间就是byte数组。
//压缩数据byte[] bytes=newCompressRedis().serialize(data);ByteArrayOutputStream baos=newByteArrayOutputStream();ObjectOutputStream oos=newObjectOutputStream(baos);
oos.writeObject(bytes);//写入 RedisJedis jedis=newJedis();
jedis.set((key.getBytes(), baos.toByteArray());//关闭流
oos.close();// 读取 Byte格式 存入的数据ByteArrayInputStream byteArrayInputStream=newByteArrayInputStream(jedis.get(key.getBytes()));ObjectInputStream objectInputStream=newObjectInputStream(byteArrayInputStream);byte[] o=(byte[]) objectInputStream.readObject();//解压数据Object object=newCompressRedis().deserialize(p);
这便成功取出了数据
总结
问题出在从redis拿出数据后进行转型导致数据损坏,所以要么避免转型的操作,直接取出需要的字节数组类型的数据,要么使用不会损坏数据的转型方式。