Mryqu's Notes


  • 首页

  • 搜索
close

序列化压缩实现及对比测试

时间: 2013-08-08   |   分类: Java     |   阅读: 869 字 ~5分钟

网上介绍序列化压缩的用gzip比较多。写个测试代码,测试一下四种序列化方式:

  • 无压缩
  • zlib压缩
  • gzip压缩
  • zip压缩

测例结果显示压缩效果:gzip压缩 > zlib压缩 > zip压缩> 无压缩 测例结果显示压缩速度:zlib压缩> gzip压缩> zip压缩 = 无压缩 确实用gzip性价比比较高!

### zlib介绍

zlib是一个开源库,提供了在内存中压缩和解压的函数。zlib它的设计目标是处理单纯的数据(而不管数据的来源是什么)。

### gzip介绍

gzip是UNIX下的一种数据格式(.tar.gz)。gzip是在zlib之上,包了一层,在头和尾添加了一些额外的信息。 gzip是一种文件压缩工具(或该压缩工具产生的压缩文件格式),它的设计目标是处理单个的文件。gzip在压缩文件中的数据时使用的就是zlib。为了保存与文件属性有关的信息,gzip需要在压缩文件(.gz)中保存更多的头信息内容,而zlib不用考虑这一点。但gzip只适用于单个文件,所以我们在UNIX/Linux上经常看到的压缩包后缀都是.tar.gz或*.tgz,也就是先用tar把多个文件打包成单个文件,再用gzip压缩的结果。

### zip介绍

zip只是一种数据结构,跟rar同级别的。zip是适用于压缩多个文件的格式(相应的工具有PkZip和WinZip等),因此,zip文件还要进一步包含文件目录结构的信息,比gzip的头信息更多。但需要注意,zip格式可采用多种压缩算法,我们常见的zip文件大多不是用zlib的算法压缩的,其压缩数据的格式与gzip大不一样。 Java SDK提供了对上述三种压缩技术的支持:Inflater类和Deflater类直接用zlib库对数据压缩/解压缩,GZIPInputStream类和GZIPOutputStream类提供了对gzip格式的支持,ZipFile、ZipInputStream、ZipOutputStream则用于处理zip格式的文件。 所以,你应当根据你的具体需求,选择不同的压缩技术:如果只需要压缩/解压缩数据,你可以直接用zlib实现,如果需要生成gzip格式的文件或解压其他工具的压缩结果,你就必须用gzip或zip等相关的类来处理了。

测试代码

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

import java.util.Arrays;

import java.util.zip.DataFormatException;
import java.util.zip.Deflater;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import java.util.zip.Inflater;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

public class TestCompressedSerializaion {

  public static BigObject createBigObject() {
    final int SIZE = 1 << 12;
    int[] bigArray = new int[SIZE];
    for (int i = 0; i < SIZE; ++i) {
      bigArray[i] = (int) (Math.random() * 100);
    }
    return new BigObject(bigArray);
  }

  public static void serializeObject(Object obj, String flName) {
    FileOutputStream fileOut = null;
    ObjectOutputStream out = null;
    try {
      fileOut = new FileOutputStream(flName);
      out = new ObjectOutputStream(fileOut);
      out.writeObject(obj);
    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      if (out != null) {
        try {
          out.close();
        } catch (Exception e) {
        }
      }
      if (fileOut != null) {
        try {
          fileOut.close();
        } catch (Exception e) {
        }
      }
    }
  }

  public static Object deserializeObject(String flName) {
    FileInputStream fileIn = null;
    ObjectInputStream in = null;
    Object res = null;
    try {
      fileIn = new FileInputStream(flName);
      in = new ObjectInputStream(fileIn);
      res = in.readObject();
    } catch (IOException ioe) {
      ioe.printStackTrace();
    } catch (ClassNotFoundException cnfe) {
      cnfe.printStackTrace();
    } finally {
      if (in != null) {
        try {
          in.close();
        } catch (Exception e) {
        }
      }
      if (fileIn != null) {
        try {
          fileIn.close();
        } catch (Exception e) {
        }
      }
    }
    return res;
  }

  public static void testCompressedSerializaion(CompressType compressType,
      BigObject bigObj) {
    CompressedSerializaion.compressType = compressType;
    String flName = compressType.name() + ".ser";
    
    long beginTime = System.currentTimeMillis();
    serializeObject(new CompressedSerializaion(bigObj), flName);
    CompressedSerializaion obj = (CompressedSerializaion) deserializeObject(flName);
    long usedTime = System.currentTimeMillis()-beginTime;
    System.out.println(flName + " length:" + new File(flName).length()
        + " usedTime:"+usedTime
        + " serialization correctness:"+ bigObj.equals(obj.getBigObj()));
  }

  public static void main(String[] args) {
    BigObject bigObj = createBigObject();
    testCompressedSerializaion(CompressType.UNCOMPRESSED, bigObj);
    testCompressedSerializaion(CompressType.ZLIB, bigObj);
    testCompressedSerializaion(CompressType.GZIP, bigObj);
    testCompressedSerializaion(CompressType.ZIP, bigObj);
  }
}

enum CompressType {
  UNCOMPRESSED, ZLIB, GZIP, ZIP
};

@SuppressWarnings("serial")
class BigObject implements Serializable {
  private int[] bigArray;
  public BigObject(int[] bigArray) {
    this.bigArray = bigArray;
  }
  public int[] getBigArray() {
    return bigArray;
  }
  public void setBigArray(int[] bigArray) {
    this.bigArray = bigArray;
  }
  @Override
  public int hashCode() {
    return Arrays.hashCode(bigArray);
  }
  @Override
  public boolean equals(Object obj) {
    if (this == obj)
      return true;
    if (obj == null)
      return false;
    if (getClass() != obj.getClass())
      return false;
    BigObject other = (BigObject) obj;
    if (!Arrays.equals(bigArray, other.bigArray))
      return false;
    return true;
  }
}

@SuppressWarnings("serial")
class CompressedSerializaion implements Serializable {
  public static CompressType compressType = CompressType.UNCOMPRESSED; 
  private BigObject bigObj;

  public CompressedSerializaion(BigObject bigObj) {
    this.bigObj = bigObj;
  }

  public BigObject getBigObj() {
    return bigObj;
  }

  public void setBigObj(BigObject bigObj) {
    this.bigObj = bigObj;
  }

  @Override
  public int hashCode() {
    return bigObj == null   0 : bigObj.hashCode();
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj)
      return true;
    if (obj == null)
      return false;
    if (getClass() != obj.getClass())
      return false;
    CompressedSerializaion other = (CompressedSerializaion) obj;
    if (!bigObj.equals(other.bigObj))
      return false;
    return true;
  }

  public void writeMyObject(ObjectOutputStream out) throws IOException {
    out.writeObject(bigObj);
  }

  private void readMyObject(ObjectInputStream ois)
      throws ClassNotFoundException, IOException {
    bigObj = (BigObject) ois.readObject();
  }

  private void writeObject(ObjectOutputStream out) throws IOException {
    if (compressType == CompressType.UNCOMPRESSED) {
      writeMyObject(out);
    } else if (compressType == CompressType.ZLIB) {
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      ObjectOutputStream baOos = new ObjectOutputStream(baos);
      writeMyObject(baOos);
      baOos.flush();
      baOos.close();
      byte unCompressedBytes[] = baos.toByteArray();
      baos.close();
      Deflater compresser = new Deflater(Deflater.BEST_SPEED);
      compresser.setInput(unCompressedBytes);
      compresser.finish();
      byte bytes[] = new byte[unCompressedBytes.length];
      int nz = compresser.deflate(bytes);
      out.writeInt(nz);
      out.write(bytes, 0, nz);
    } else {
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      if (compressType == CompressType.GZIP) {
        GZIPOutputStream gzos = new GZIPOutputStream(baos);
        ObjectOutputStream gzOos = new ObjectOutputStream(gzos);
        writeMyObject(gzOos);
        gzOos.flush();
        gzos.close();
      } else {
        ZipOutputStream zos = new ZipOutputStream(baos);
        ZipEntry ze = new ZipEntry("testZipSerializaion");
        zos.setLevel(Deflater.BEST_SPEED);
        zos.putNextEntry(ze);
        ObjectOutputStream zipOos = new ObjectOutputStream(zos);
        writeMyObject(zipOos);
        zipOos.flush();
        zos.closeEntry();
        zos.close();
      }
      byte bytes[] = baos.toByteArray();
      int nz = baos.size();
      baos.close();
      out.writeInt(nz);
      out.write(bytes, 0, nz);
    }
  }

  private void readObject(ObjectInputStream ois)
      throws ClassNotFoundException, IOException {
    if (compressType == CompressType.UNCOMPRESSED) {
      readMyObject(ois);
    } else {
      int nz = ois.readInt();
      byte bytes[] = new byte[nz];
      int totalSize = 0;
      while (totalSize < nz) {
        // attempt to read the entire buffer in a single read
        int bytesRead = ois.read(bytes, totalSize, (nz - totalSize));
        if (bytesRead == -1) // EOF
          break;
        totalSize += bytesRead;
      }
      if (compressType == CompressType.ZLIB) {
        Inflater decompresser = new Inflater();
        decompresser.setInput(bytes, 0, nz);
        byte[] unCompressedBytes;
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
          byte[] buf = new byte[1024];
          while (!decompresser.finished()) {
            int i = decompresser.inflate(buf);
            baos.write(buf, 0, i);
          }
          unCompressedBytes = baos.toByteArray();
        } catch (DataFormatException e) {
          throw new IOException(e);
        } finally {
          try {
            baos.close();
            decompresser.end();
          } finally {
          }
        }
        ByteArrayInputStream bais = new ByteArrayInputStream(
            unCompressedBytes);
        ObjectInputStream baOis = new ObjectInputStream(bais);
        readMyObject(baOis);
        bais.close();
      } else if (compressType == CompressType.GZIP) {
        ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
        GZIPInputStream zis = new GZIPInputStream(bais);
        ObjectInputStream zipOis = new ObjectInputStream(zis);
        readMyObject(zipOis);
        bais.close();
      } else if (compressType == CompressType.ZIP) {
        ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
        ZipInputStream zis = new ZipInputStream(bais);
        // open first zip file entry
        ZipEntry ze = zis.getNextEntry();
        ObjectInputStream zipOis = new ObjectInputStream(zis);
        readMyObject(zipOis);
        bais.close();
      }
    }
  }
}

测试结果

UNCOMPRESSED.ser length:16582 usedTime:14 serialization correctness:true
ZLIB.ser length:6108 usedTime:4 serialization correctness:true
GZIP.ser length:5682 usedTime:5 serialization correctness:true
ZIP.ser length:6254 usedTime:14 serialization correctness:true

标题:序列化压缩实现及对比测试
作者:mryqu
声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 CN 许可协议。转载请注明出处!

#序列化# #压缩# #zlib# #gzip# #zip#
JDK7中的双端队列Deque实现
JDK7中的队列实现
  • 文章目录
  • 站点概览

Programmer & Architect

662 日志
27 分类
1472 标签
GitHub Twitter FB Page
    • 测试代码
    • 测试结果
© 2009 - 2023 Mryqu's Notes
Powered by - Hugo v0.120.4
Theme by - NexT
0%