1

現在、java.util.zip.*パッケージを使用して可逆圧縮/解凍を実行しようとしています。

そして、Apacheのjarを使用して、Base64文字セットで引数として使用される文字列をエンコードおよびデコードしました。

私のコードでは、圧縮用と解凍用の 2 つの静的メソッドを使用しています。

import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.zip.*;

import org.apache.commons.codec.binary.Base64;

public class main {

    public String compress(String stringToCompress) throws UnsupportedEncodingException
    {       
        //System.out.println("String to Be Compressed :: " + stringToCompress);
        byte[] input = Base64.decodeBase64(stringToCompress);

        Deflater compressor = new Deflater();
        compressor.setInput(input);
        compressor.finish();

        byte[] output = new byte[100];
        compressor.deflate(output);
        return Base64.encodeBase64String(output);
    }

    public String decompressToString(String stringToDecompress) throws UnsupportedEncodingException, DataFormatException
    {   
        //System.out.println("String to be Decompressed :: " + stringToDecompress);
        byte[] input = Base64.decodeBase64(stringToDecompress);

        Inflater deCompressor = new Inflater();
        deCompressor.setInput(input,0,input.length);

        byte[] output = new byte[100];
        deCompressor.inflate(output);
        deCompressor.end();

        return Base64.encodeBase64String(output);
    }


    public static void main(String[] args) throws UnsupportedEncodingException, DataFormatException {
        main m = new main();
        String strToBeCompressed  = "jhjksdhgfkjdsfhkjhjvblkajnlkdfmvlksjfdovbjaiudhv adjv ajgvoig avigogauguivadfhijbjkla";
        String compressedString  = m.compress(strToBeCompressed) ;
        String deCompressedString = m.decompressToString(compressedString);

        System.out.println("Original :: " + strToBeCompressed);
        System.out.println("Compressed :: " + compressedString);
        System.out.println("decompressed :: " + deCompressedString);
    }
}

これが出力です。

Original :: jhjksdhgfkjdsfhkjhjvblkajnlkdfmvlksjfdovbjaiudhv adjv ajgvoig avigogauguivadfhijbjkla
Compressed :: eJwBPQDC/44Y5LHYYH5I3bH4ZI4Y725ZGo55ZHX5r5ZLI33aL242ornYb2nY72o4L6IoGr4oKIGroLor2nX4Yo245JXcvx/9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
decompressed :: jhjksdhgfkjdsfhkjhjvblkajnlkdfmvlksjfdovbjaiudhvadjvajgvoigavigogauguivadfhijbjklQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==

出力が表示される場合、元の文字列と解凍された文字列が一致していません。どうしてか分かりません?だれか理由を教えてください。

4

2 に答える 2

3

懸念を分離し、圧縮、圧縮解除、base 64 エンコード、および base64 デコードを別の方法で別の懸念として扱うべきだと思います。あなたが Base64 を使用している理由を推測することはできません - おそらく正当な理由があるのでしょう。圧縮された文字列を Base64 でエンコードしたいですか?

とにかく、損失なしで文字列を圧縮および圧縮解除できるコードのバージョンを次に示します (ただし、Base64 は関係ありません)。

package dk.tbsalling.stackoverflow;

import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.zip.*;

import org.apache.commons.codec.binary.Base64;

public class App
{
    private byte[] compress(String stringToCompress) throws UnsupportedEncodingException
    {
        byte[] compressedData = new byte[1024];
        byte[] stringAsBytes = stringToCompress.getBytes("UTF-8");

        Deflater compressor = new Deflater();
        compressor.setInput(stringAsBytes);
        compressor.finish();
        int compressedDataLength = compressor.deflate(compressedData);

        return Arrays.copyOf(compressedData, compressedDataLength);
    }

    private String decompressToString(byte[] compressedData) throws UnsupportedEncodingException, DataFormatException
    {   
        Inflater deCompressor = new Inflater();
        deCompressor.setInput(compressedData, 0, compressedData.length);
        byte[] output = new byte[1024];
        int decompressedDataLength = deCompressor.inflate(output);
        deCompressor.end();

        return new String(output, 0, decompressedDataLength, "UTF-8");
    }

    public static void main(String[] args) throws UnsupportedEncodingException, DataFormatException {
        App m = new App();
        String strToBeCompressed  = "jhjksdhgfkjdsfhkjhjvblkajnlkdfmvlksjfdovbjaiudhv adjv ajgvoig avigogauguivadfhijbjkla";
        byte[] compressedData  = m.compress(strToBeCompressed);
        String deCompressedString = m.decompressToString(compressedData);

        System.out.println("Original     :: " + strToBeCompressed.length() + " " + strToBeCompressed);
        System.out.println("Compressed   :: " + compressedData.toString());
        System.out.println("decompressed :: " + deCompressedString.length() + " " + deCompressedString);
    }
}

これにより、次の出力が生成されます。

Original     :: 85 jhjksdhgfkjdsfhkjhjvblkajnlkdfmvlksjfdovbjaiudhv adjv ajgvoig avigogauguivadfhijbjkla
Compressed   :: [B@3ced0338
decompressed :: 85 jhjksdhgfkjdsfhkjhjvblkajnlkdfmvlksjfdovbjaiudhv adjv ajgvoig avigogauguivadfhijbjkla

Process finished with exit code 0

アップデート

圧縮文字列の Base64 エンコード表現を生成するコードを次に示します。

package dk.tbsalling.stackoverflow;

import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.zip.*;

import org.apache.commons.codec.binary.Base64;

public class App
{
    private String compress(String stringToCompress) throws UnsupportedEncodingException
    {
        byte[] compressedData = new byte[1024];
        byte[] stringAsBytes = stringToCompress.getBytes("UTF-8");

        Deflater compressor = new Deflater();
        compressor.setInput(stringAsBytes);
        compressor.finish();
        int compressedDataLength = compressor.deflate(compressedData);

        byte[] bytes = Arrays.copyOf(compressedData, compressedDataLength);
        return Base64.encodeBase64String(bytes);
    }

    private String decompressToString(String base64String) throws UnsupportedEncodingException, DataFormatException
    {
        byte[] compressedData = Base64.decodeBase64(base64String);

        Inflater deCompressor = new Inflater();
        deCompressor.setInput(compressedData, 0, compressedData.length);
        byte[] output = new byte[1024];
        int decompressedDataLength = deCompressor.inflate(output);
        deCompressor.end();

        return new String(output, 0, decompressedDataLength, "UTF-8");
    }

    public static void main(String[] args) throws UnsupportedEncodingException, DataFormatException {
        App m = new App();
        String strToBeCompressed  = "jhjksdhgfkjdsfhkjhjvblkajnlkdfmvlksjfdovbjaiudhv adjv ajgvoig avigogauguivadfhijbjkla";
        String compressedData  = m.compress(strToBeCompressed);
        String deCompressedString = m.decompressToString(compressedData);

        System.out.println("Original     :: " + strToBeCompressed.length() + " " + strToBeCompressed);
        System.out.println("Compressed   :: " + compressedData.toString());
        System.out.println("decompressed :: " + deCompressedString.length() + " " + deCompressedString);
    }
}

これにより、次の出力が生成されます。

Original     :: 85 jhjksdhgfkjdsfhkjhjvblkajnlkdfmvlksjfdovbjaiudhv adjv ajgvoig avigogauguivadfhijbjkla
Compressed   :: eJwNxMkNwDAIBMBW3BoW4lhI/LDY+pN5DAJ1NdwKei0KAe4uwdul9rDrwvRwQ3I0uETxB+dJX8L04zI+SVGLxEa1fNDSIlU=
decompressed :: 85 jhjksdhgfkjdsfhkjhjvblkajnlkdfmvlksjfdovbjaiudhv adjv ajgvoig avigogauguivadfhijbjkla

Process finished with exit code 0
于 2013-06-14T11:13:40.767 に答える
3

バッファの問題

compress()との両方の出力バッファのdecompressToString()サイズは 100 に固定されています。ただし、出力は 100 バイトより小さいため、配列の最後は使用されません (ゼロでいっぱいです)。これを Base64 に変換すると、ゼロがA文字として出力されます ( ==is padding )。

データを含むバッファーの部分のみを考慮し、残りは無視する必要があります。メソッドinflate()とメソッドdeflate()は、それらが埋めたバイト数を返します。残念ながら、Apache の Base64 コンバーターは配列内の範囲をサポートしていないため、バッファーのサイズを変更する必要があります。

byte[] output = new byte[100];
int size = compressor.deflate(output);
output = Arrays.copyOf(output, size);

についても同様ですdecompressToString()

これにより、バッファが完全にいっぱいにならないという問題は解決されますが、さらに大きな問題が発生します。バッファがオーバーフローする可能性があります。圧縮または解凍された文字列のサイズが 100 バイトを超える場合は、すべてのデータを取得するためにinflate()deflate()複数回呼び出す必要があります。

ベース 64 の問題

現在、への入力文字列compress()は Base64 文字列として解釈されます。同様に、から返される文字列はdecompressToString()、Base64 文字列としてエンコードされたデータです。

あなたの意図は、元の文字列を無制限にすることだと思います。では、単純に を使用compress()して入力文字列からバイト配列を取得する代わりに、 を使用します。で逆が発生するはずです: に変更します。コピーを作成する代わりに、String(byte[] bytes, int offset, int length)オーバーロードを使用して、出力配列の部分範囲を指定できます。Base64.decodeBase64(stringToCompress)stringToCompress.getBytes()decompressToString()Base64.encodeBase64String(output)new String(output)

完全なコード

import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.zip.*;
import java.util.*;

import org.apache.commons.codec.binary.Base64;

public class main {

    public String compress(String stringToCompress) throws UnsupportedEncodingException
    {
        //System.out.println("String to Be Compressed :: " + stringToCompress);
        byte[] input = stringToCompress.getBytes();

        Deflater compressor = new Deflater();
        compressor.setInput(input);
        compressor.finish();

        byte[] output = new byte[100];
        int size = compressor.deflate(output);
        output = Arrays.copyOf(output, size);
        return Base64.encodeBase64String(output);
    }

    public String decompressToString(String stringToDecompress) throws UnsupportedEncodingException, DataFormatException
    {
        //System.out.println("String to be Decompressed :: " + stringToDecompress);
        byte[] input = Base64.decodeBase64(stringToDecompress);

        Inflater deCompressor = new Inflater();
        deCompressor.setInput(input,0,input.length);

        byte[] output = new byte[100];
        int size = deCompressor.inflate(output);
        deCompressor.end();

        return new String(output, 0, size);
    }


    public static void main(String[] args) throws UnsupportedEncodingException, DataFormatException {
        main m = new main();
        String strToBeCompressed  = "jhjksdhgfkjdsfhkjhjvblkajnlkdfmvlksjfdovbjaiudhv adjv ajgvoig avigogauguivadfhijbjkla";
        String compressedString  = m.compress(strToBeCompressed) ;
        String deCompressedString = m.decompressToString(compressedString);

        System.out.println("Original :: " + strToBeCompressed);
        System.out.println("Compressed :: " + compressedString);
        System.out.println("decompressed :: " + deCompressedString);
    }
}

差分

@@ -3,2 +3,3 @@
 import java.util.zip.*;
+import java.util.*;

@@ -11,3 +12,3 @@
         //System.out.println("String to Be Compressed :: " + stringToCompress);
-        byte[] input = Base64.decodeBase64(stringToCompress);
+        byte[] input = stringToCompress.getBytes();

@@ -18,3 +19,4 @@
         byte[] output = new byte[100];
-        compressor.deflate(output);
+        int size = compressor.deflate(output);
+        output = Arrays.copyOf(output, size);
         return Base64.encodeBase64String(output);
@@ -31,6 +33,6 @@
         byte[] output = new byte[100];
-        deCompressor.inflate(output);
+        int size = deCompressor.inflate(output);
         deCompressor.end();

-        return Base64.encodeBase64String(output);
+        return new String(output, 0, size);
     }
于 2013-06-14T10:15:29.907 に答える