Perché non riesco a ottenere la mia stringa originale dopo la compressione e la decompressione?

Attualmente sto cercando di utilizzare il pacchetto java.util.zip. * Per eseguire la compressione / decompressione senza perdita di dati.

E ho usato il jar di Apache per codificare e decodificare la stringa utilizzata come argomento nel set di caratteri Base64.

Seguendo il mio codice con due metodi statici uno per compressione e uno per decompressione.

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); } } 

Ecco l’output.

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

Se vedi l’output, la stringa originale e quella decompressa non corrispondono. Non so perché? Qualcuno può dirmi la ragione.

Penso che dovresti separare le preoccupazioni e trattare la compressione, la decompressione, la codifica base 64 e la decodifica base64 come preoccupazioni separate in metodi separati. Non sono in grado di dedurre perché hai coinvolto Base64 – forse c’è una buona ragione. Forse vuoi che la stringa compressa sia codificata Base64?

Ad ogni modo, ecco una versione del tuo codice che può comprimere e decomprimere la stringa senza alcuna perdita (ma nessun Base64 coinvolto):

 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); } } 

Questo produce output:

 Original :: 85 jhjksdhgfkjdsfhkjhjvblkajnlkdfmvlksjfdovbjaiudhv adjv ajgvoig avigogauguivadfhijbjkla Compressed :: [[email protected] decompressed :: 85 jhjksdhgfkjdsfhkjhjvblkajnlkdfmvlksjfdovbjaiudhv adjv ajgvoig avigogauguivadfhijbjkla Process finished with exit code 0 

AGGIORNARE

Ecco il codice per produrre la rappresentazione codificata Base64 della stringa compressa:

 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); } } 

Questo produce output:

 Original :: 85 jhjksdhgfkjdsfhkjhjvblkajnlkdfmvlksjfdovbjaiudhv adjv ajgvoig avigogauguivadfhijbjkla Compressed :: eJwNxMkNwDAIBMBW3BoW4lhI/LDY+pN5DAJ1NdwKei0KAe4uwdul9rDrwvRwQ3I0uETxB+dJX8L04zI+SVGLxEa1fNDSIlU= decompressed :: 85 jhjksdhgfkjdsfhkjhjvblkajnlkdfmvlksjfdovbjaiudhv adjv ajgvoig avigogauguivadfhijbjkla Process finished with exit code 0 

Problemi di buffer

Il buffer di output per compress() e decompressToString() ha una dimensione fissa di 100. L’output è tuttavia inferiore a 100 byte, quindi la fine dell’array sarà inutilizzata (piena di zeri). Quando questo viene tradotto in Base64 gli zeri vengono visualizzati come caratteri A (il == è padding ).

È necessario considerare solo la parte del buffer che contiene dati e ignorare il resto. I metodi inflate() e deflate() restituiscono il numero di byte che hanno riempito. Sfortunatamente il convertitore Base64 di Apache non supporta gli intervalli all’interno di un array, quindi dovrai ridimensionare il buffer:

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

e allo stesso modo per decompressToString() .

Questo risolve il problema del buffer che non si riempie completamente ma solleva un problema ancora più grande: il buffer potrebbe traboccare. Se la dimensione della stringa compressa o decompressa è superiore a 100 byte, è necessario chiamare inflate() e deflate() più volte per ottenere tutti i dati.

Base 64 Problemi

Attualmente, la stringa di input da compress() viene interpretata come una stringa Base64. Allo stesso modo, la stringa restituita da decompressToString() è codificata come una stringa Base64.

Penso che la tua intenzione sia che la stringa originale non sia ristretta. In compress() , invece di ottenere l’array di byte dalla stringa di input utilizzando Base64.decodeBase64(stringToCompress) sufficiente utilizzare stringToCompress.getBytes() . Il contrario dovrebbe avvenire in decompressToString() : modifica Base64.encodeBase64String(output) in new String(output) . È ansible utilizzare il sovraccarico String (byte [] byte, int offset, lunghezza int) per specificare un subrange dell’array di output anziché creare una copia.

Codice completo

 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); } } 

diff

 @@ -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); }