2

簡単にString分解できますbyte[]

        String s = "my string";
        byte[] b = s.getBytes();
        System.out.println(new String(b)); // my string

ただし、圧縮が関係する場合、いくつかの問題があるようです。2 つのメソッドがあるとしますcompress(uncompress以下のコードは正常に動作します)。

public static byte[] compress(String data) 
             throws UnsupportedEncodingException, IOException {
    byte[] input = data.getBytes("UTF-8");
    Deflater df = new Deflater();
    df.setLevel(Deflater.BEST_COMPRESSION);
    df.setInput(input);

    ByteArrayOutputStream baos = new ByteArrayOutputStream(input.length);
    df.finish();
    byte[] buff = new byte[1024];
    while (!df.finished()) {
        int count = df.deflate(buff);
        baos.write(buff, 0, count);
    }
    baos.close();
    byte[] output = baos.toByteArray();

    return output;
}

public static String uncompress(byte[] input) 
            throws UnsupportedEncodingException, IOException,
        DataFormatException {
    Inflater ifl = new Inflater();
    ifl.setInput(input);

    ByteArrayOutputStream baos = new ByteArrayOutputStream(input.length);
    byte[] buff = new byte[1024];
    while (!ifl.finished()) {
        int count = ifl.inflate(buff);
        baos.write(buff, 0, count);
    }
    baos.close();
    byte[] output = baos.toByteArray();

    return new String(output);
}

私のテストは次のように機能します(正常に動作します)

String text = "some text";
byte[] bytes = Compressor.compress(text);
assertEquals(Compressor.uncompress(bytes), text); // works

それ以外の理由ではありませんが、最初のメソッドを変更して、String代わりにa を返すようにしたいと思いますbyte[].

だから私return new String(output)compressメソッドから私のテストを次のように変更します:

String text = "some text";
String compressedText = Compressor.compress(text);
assertEquals(Compressor.uncompress(compressedText.getBytes), text); //fails

このテストは失敗しますjava.util.zip.DataFormatException: incorrect header check

何故ですか?それを機能させるために何をする必要がありますか?

4

2 に答える 2

4

String(byte[])コンストラクタが問題です。単純に任意のバイトを取り、それらを文字列に変換してからバイト配列に戻すことはできません。Stringクラスはbyte、目的の文字セットに基づいて、これに対して高度なエンコーディングを実行します。指定されたバイト シーケンスが Unicode などで表現できない場合、破棄されるか、別のものに変換されます。バイトからバイトへの変換Stringとその逆の変換は、これらのバイトが実際に (何らかのエンコーディングで)bytes表現されている場合にのみ無損失です。String

最も簡単な例を次に示します。

new String(new byte[]{-128}, "UTF-8").getBytes("UTF-8")

入力がまったく同じ出力を返す-17, -65, -67間、上記は戻ります。127

于 2012-08-01T15:55:45.967 に答える
1

プラットフォームの現在のエンコーディングを使用してバイトから文字列に変換するだけなので、失敗します。そのため、ほとんどのバイトは同等の文字コードに変換されますが、現在のエンコーディングによっては、一部が他のコードに置き換えられる場合があります。バイトに何が起こるかを確認するには、次を実行します。

byte[] b = new byte[256];
for(int i = 0; i < b.length; ++i) {
    b[i] = (byte)i;
}
String s = new String(b);

for(int i = 0; i< s.length(); ++i) {
    System.out.println(i + ": " + s.substring(i, i+1) + " " + (int)s.charAt(i));
}

ご覧のとおり、これをバイトに戻すと、一部のコードはすべて同じ値になります。また、このサンプルは、文字が UTF-8 のように複数のコードでエンコードされているエンコーディングを処理しません。

一般に、適切なエンコーディング パラメータを指定せずにString.getBytes()andを呼び出すことは避けるべきです。new String(byte[])また、独自にコーディングしない限り、各バイトが対応する文字コードになる 1 対 1 のエンコーディングはありません。

圧縮されたデータを文字列として扱いたい場合は、base64 表現または 16 進ダンプを使用してください。ただし、文字列表現には 2 倍のメモリが必要であり、base64 では 4/3 倍、16 進数では 2 倍のメモリが必要になることに注意してください。これにより、圧縮の利点が失われる可能性があります。

于 2012-08-01T16:06:17.563 に答える