Java Inflate与大字符串不一致

时间:2013-12-17 12:13:52

标签: java compression inflate deflate

我想使用java.util.zip包恢复压缩的中等长度字符串(665个字符),压缩是通过以下代码进行的:

public String compress(String s){
    Deflater def = new Deflater(9);
    byte[] buffer = new byte[s.length()];
    String rta = "";
    def.setInput(s.getBytes());
    def.finish();
    def.deflate(buffer);
    rta = new String(buffer);
    rta = rta.trim().concat("*" + Integer.toString(s.length()));
  //this addition at the end is used to recover the original length of the string to dynamically create the buffer later on.
    return rta;
}

解压缩的代码是:

public String decompress(String s){
    String rta = "";
    Inflater inf = new Inflater();
    byte[] buffer = separoArray(s, true).getBytes(); // This function returns the compressed string or the original length wheter true/false parameter
    int len = Integer.valueOf(separoArray(s, false));
    byte[] decomp = new byte[len];
    inf.setInput(buffer);
    try {
        inf.inflate(decomp, 0, len);
        inf.end();
    } catch (DataFormatException e) {e.printStackTrace();}
    rta = new String(decomp);
    return rta;
}

这是原始字符串和解压缩字符串:

原件:

“Lorem ipsum dolor sit amet,consectetur adipiscing elit.Sed rutrum imperdiet consequat.Nulla eu sapien tincidunt,pellentesque ipsum in,luctus eros.Nullam tristique arcu lorem,fringilla lectus tincidunt sit amet.Ut tortor dui,cursus at erat在hac habitasse platea dictumst.Nulla facilisi.Duis eget auctor nibh.Cras ante odio,dignissim et sem id,ultrices imperdiet erat.Aenean ut purus hendrerit,bibendum massa non,accumsan orci.Morbi quis leo sed mauris scelerisque vulputate.fusce gravida facilisis ipsum pellentesque euismod。Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae“

解压缩:

“Lorem ipsuAdolor sit amet,consectetur adipiscing elit.Sed rutrsuAimperdiet consequat.Nulla eu sapien tincidunt,pellentesquem ipsuAin,luctus eros.Nullam tristiquemarcu lLore,fringilla lectus tincidunt sit amet.Ut tortor dui,cursus at erat non,interdsuAimperdiet odsAimpeIn HAC habitasse platea DIUS毫秒法无eufacilisi。Duierog odatus dunibh。Craat erddsAim,dignissim的odsm IPD,ulistcesmperdiet ODATñ。Aenean UT PUR athendreri pebibendAimmassaon,inacc MSAN奥奇。Morbi quierleodsmdmmausti sceleriuem ivulputate。Fusce gravideufacilisisipsuAinllentesquem ieuiemod。VeiqubulAin erddpsuAinlrimisipnufaucubus orciuctus EROT ulistcesmposuereursbilia库拉“< / p>

差异是显而易见的,为什么会发生这种情况?,我该怎么做才能避免它?

谢谢。

2 个答案:

答案 0 :(得分:3)

我同意评论者的意见,压缩字符串最好是byte[]。 但是,对于像ISO-8859-1这样的单字节编码,可能会在byte[]String之间进行滥用。

以下内容与您的版本不同,因为它明确指出了编码。对于文本,UTF-8足以没有限制并覆盖整个Unicode范围。

请注意deflate返回值的使用情况。

public static String compress(String s) {
    Deflater def = new Deflater(9);
    byte[] sbytes = s.getBytes(StandardCharsets.UTF_8);
    def.setInput(sbytes);
    def.finish();
    byte[] buffer = new byte[sbytes.length];
    int n = def.deflate(buffer);
    return new String(buffer, 0, n, StandardCharsets.ISO_8859_1)
            + "*" + sbytes.length;
}

public static String decompress(String s) {
    int pos = s.lastIndexOf('*');
    int len = Integer.parseInt(s.substring(pos + 1));
    s = s.substring(0, pos);

    Inflater inf = new Inflater();
    byte[] buffer = s.getBytes(StandardCharsets.ISO_8859_1);
    byte[] decomp = new byte[len];
    inf.setInput(buffer);
    try {
        inf.inflate(decomp, 0, len);
        inf.end();
    } catch (DataFormatException e) {
        throw new IllegalArgumentException(e);
    }
    return new String(decomp, StandardCharsets.UTF_8);
}

答案 1 :(得分:2)

Deflater问题

主要问题是这一行:

    rta = new String(buffer);

您正在使用平台的默认字符编码将字节数组(表示压缩输入字符串)和解码变为字符串。这是错的。对于大多数字符编码,存在无法映射到字符的字节值序列的字节值。当你试图&#34;解码&#34;如果字节不能代表正确编码的文本,则可能会在整个字符串中散布问号或其他字符。这会导致信息丢失......而且无法恢复信息。

(有一个或两个字符集,其中解码/编码是完全可逆的...你可以使用其中一个作为编码方案,将压缩字节转换为&#34; text&#34;。但是& #39;不是结束!)

关于如何处理压缩字节的第二个问题。 deflate(byte[] buffer)方法压缩输入数据并将压缩输出写入buffer。但是,不能保证N个字节的输入将导致N个字节的输出。相反,deflate方法返回一个int,给出写入buffer的字节数。

但是你的代码然后占用了整个buffer ...包括不是写的字节...并将其转换成字符串(通过不健全的程序)如上所述)。然后你trim字符串(我推测)摆脱尾随的NUL字符。但是这将从开头和结尾修剪所有空白区域,其中一些字符可能是压缩字符串的重要部分。


基本上,你正在做的是不健全。您不应该尝试将任意字节转换为String。压缩数据不是文本。

我的建议是执行以下操作之一:

  • 不要将(压缩的)byte[]转换为String。将其保留为byte[] ...并正确处理长度问题。

  • 或者,使用无损字节字符编码方案;例如十六进制编码或base64编码。