Java 使用deflater压缩/解压缩字符串

Java 使用deflater压缩/解压缩字符串,java,compression,Java,Compression,我想压缩/解压缩和序列化/反序列化字符串内容。我使用以下两个静态函数 /** * Compress data based on the {@link Deflater}. * * @param pToCompress * input byte-array * @return compressed byte-array * @throws NullPointerException * if {@code pToCompress} is

我想压缩/解压缩和序列化/反序列化字符串内容。我使用以下两个静态函数

/**
 * Compress data based on the {@link Deflater}.
 * 
 * @param pToCompress
 *            input byte-array
 * @return compressed byte-array
 * @throws NullPointerException
 *             if {@code pToCompress} is {@code null}
 */
public static byte[] compress(@Nonnull final byte[] pToCompress) {
    checkNotNull(pToCompress);

    // Compressed result.
    byte[] compressed = new byte[] {};

    // Create the compressor.
    final Deflater compressor = new Deflater();
    compressor.setLevel(Deflater.BEST_SPEED);

    // Give the compressor the data to compress.
    compressor.setInput(pToCompress);
    compressor.finish();

    /*
     * Create an expandable byte array to hold the compressed data.
     * You cannot use an array that's the same size as the orginal because
     * there is no guarantee that the compressed data will be smaller than
     * the uncompressed data.
     */
    try (ByteArrayOutputStream bos = new ByteArrayOutputStream(pToCompress.length)) {
        // Compress the data.
        final byte[] buf = new byte[1024];
        while (!compressor.finished()) {
            final int count = compressor.deflate(buf);
            bos.write(buf, 0, count);
        }

        // Get the compressed data.
        compressed = bos.toByteArray();
    } catch (final IOException e) {
        LOGWRAPPER.error(e.getMessage(), e);
        throw new RuntimeException(e);
    }


    return compressed;
}

/**
 * Decompress data based on the {@link Inflater}.
 * 
 * @param pCompressed
 *            input string
 * @return compressed byte-array
 * @throws NullPointerException
 *             if {@code pCompressed} is {@code null}
 */
public static byte[] decompress(@Nonnull final byte[] pCompressed) {
    checkNotNull(pCompressed);

    // Create the decompressor and give it the data to compress.
    final Inflater decompressor = new Inflater();
    decompressor.setInput(pCompressed);

    byte[] decompressed = new byte[] {};

    // Create an expandable byte array to hold the decompressed data.
    try (final ByteArrayOutputStream bos = new ByteArrayOutputStream(pCompressed.length)) {
        // Decompress the data.
        final byte[] buf = new byte[1024];
        while (!decompressor.finished()) {
            try {
                final int count = decompressor.inflate(buf);
                bos.write(buf, 0, count);
            } catch (final DataFormatException e) {
                LOGWRAPPER.error(e.getMessage(), e);
                throw new RuntimeException(e);
            }
        }
        // Get the decompressed data.
        decompressed = bos.toByteArray();
    } catch (final IOException e) {
        LOGWRAPPER.error(e.getMessage(), e);
    }

    return decompressed;
}
然而,与非压缩值相比,它的数量级较慢,即使我正在缓存解压缩的结果,并且只有在确实需要内容时才解压缩这些值

也就是说,它用于类似DOM的持久化树结构和XPath查询,这些查询强制解压缩字符串值,如果不是更慢的话(不是真正的基准测试,只是执行的单元测试),也就是大约50倍。我的笔记本电脑甚至在一些单元测试后(每次检查大约5次)冻结,因为Eclipse不再响应,原因是磁盘I/O过多,等等。我甚至将压缩级别设置为
Deflater.BEST\u SPEED
,而其他压缩级别可能更好,也许我提供了一个可为
资源设置的配置选项参数。也许我把事情弄糟了,因为我以前没用过放气器。我甚至只压缩字符串长度大于10的内容


编辑:在考虑将Deflater实例化提取到一个静态字段后,创建Deflater和inflater的实例似乎成本非常高,因为性能瓶颈已经消失,也许没有微基准点之类的东西,我看不到任何性能损失:-)我只是在使用新字段之前重置Deflater/inflater输入。

您如何考虑使用更高级别的api,如Gzip

下面是一个压缩示例:

public static byte[] compressToByte(final String data, final String encoding)
    throws IOException
{
    if (data == null || data.length == 0)
    {
        return null;
    }
    else
    {
        byte[] bytes = data.getBytes(encoding);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        GZIPOutputStream os = new GZIPOutputStream(baos);
        os.write(bytes, 0, bytes.length);
        os.close();
        byte[] result = baos.toByteArray();
        return result;
    }
}
public static String unCompressString(final byte[] data, final String encoding)
    throws IOException
{
    if (data == null || data.length == 0)
    {
        return null;
    }
    else
    {
        ByteArrayInputStream bais = new ByteArrayInputStream(data);
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        GZIPInputStream is = new GZIPInputStream(bais);
        byte[] tmp = new byte[256];
        while (true)
        {
            int r = is.read(tmp);
            if (r < 0)
            {
                break;
            }
            buffer.write(tmp, 0, r);
        }
        is.close();

        byte[] content = buffer.toByteArray();
        return new String(content, 0, content.length, encoding);
    }
}
以下是一个解压缩示例:

public static byte[] compressToByte(final String data, final String encoding)
    throws IOException
{
    if (data == null || data.length == 0)
    {
        return null;
    }
    else
    {
        byte[] bytes = data.getBytes(encoding);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        GZIPOutputStream os = new GZIPOutputStream(baos);
        os.write(bytes, 0, bytes.length);
        os.close();
        byte[] result = baos.toByteArray();
        return result;
    }
}
public static String unCompressString(final byte[] data, final String encoding)
    throws IOException
{
    if (data == null || data.length == 0)
    {
        return null;
    }
    else
    {
        ByteArrayInputStream bais = new ByteArrayInputStream(data);
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        GZIPInputStream is = new GZIPInputStream(bais);
        byte[] tmp = new byte[256];
        while (true)
        {
            int r = is.read(tmp);
            if (r < 0)
            {
                break;
            }
            buffer.write(tmp, 0, r);
        }
        is.close();

        byte[] content = buffer.toByteArray();
        return new String(content, 0, content.length, encoding);
    }
}
公共静态字符串解压缩字符串(最终字节[]数据,最终字符串编码)
抛出IOException
{
if(data==null | | data.length==0)
{
返回null;
}
其他的
{
ByteArrayInputStream bais=新的ByteArrayInputStream(数据);
ByteArrayOutputStream缓冲区=新建ByteArrayOutputStream();
GZIPInputStream is=新的GZIPInputStream(BAI);
字节[]tmp=新字节[256];
while(true)
{
int r=正在读取(tmp);
if(r<0)
{
打破
}
写缓冲区(tmp,0,r);
}
is.close();
字节[]内容=缓冲区。toByteArray();
返回新字符串(content,0,content.length,encoding);
}
}
我们得到了非常好的性能和压缩比与此


zip api也是一个选项。

您的评论是正确的答案

通常,如果要频繁使用某个方法,则需要消除任何数据分配和复制。这通常意味着删除静态变量或构造函数的实例初始化和其他设置

使用静态比较容易,但您可能会遇到生命周期问题(例如,您如何知道何时清理静态-它们是否永远存在?)


在构造函数中进行设置和初始化允许类的用户确定对象的生存期并进行适当的清理。您可以在进入处理循环之前实例化它一次,并在退出后对其进行GC

您如何衡量压缩和解压缩算法的性能?你能分享一下你的想法/代码吗?您正在计算算法的压缩比和压缩时间吗?如果是这样,你能和我分享一下经验吗?我已经为随机字符串实现了压缩和解压缩算法,现在我需要通过计算压缩比、压缩时间等来衡量算法的性能。任何帮助都将不胜感激。谢谢