J'utilise le code suivant pour compresser et décompresser des données de chaîne, mais le problème auquel je suis confronté est qu'il est facilement compressé sans erreur, mais la méthode de décompression renvoie l'erreur suivante.
Exception dans le fil "principal" Java.io.IOException: Pas au format GZIP
public static void main(String[] args) throws Exception {
String string = "I am what I am hhhhhhhhhhhhhhhhhhhhhhhhhhhhh"
+ "bjggujhhhhhhhhh"
+ "rggggggggggggggggggggggggg"
+ "esfffffffffffffffffffffffffffffff"
+ "esffffffffffffffffffffffffffffffff"
+ "esfekfgy enter code here`etd`enter code here wdd"
+ "heljwidgutwdbwdq8d"
+ "skdfgysrdsdnjsvfyekbdsgcu"
+"jbujsbjvugsduddbdj";
System.out.println("after compress:");
String compressed = compress(string);
System.out.println(compressed);
System.out.println("after decompress:");
String decomp = decompress(compressed);
System.out.println(decomp);
}
public static String compress(String str) throws Exception {
if (str == null || str.length() == 0) {
return str;
}
System.out.println("String length : " + str.length());
ByteArrayOutputStream obj=new ByteArrayOutputStream();
GZIPOutputStream gzip = new GZIPOutputStream(obj);
gzip.write(str.getBytes("UTF-8"));
gzip.close();
String outStr = obj.toString("UTF-8");
System.out.println("Output String length : " + outStr.length());
return outStr;
}
public static String decompress(String str) throws Exception {
if (str == null || str.length() == 0) {
return str;
}
System.out.println("Input String length : " + str.length());
GZIPInputStream gis = new GZIPInputStream(new ByteArrayInputStream(str.getBytes("UTF-8")));
BufferedReader bf = new BufferedReader(new InputStreamReader(gis, "UTF-8"));
String outStr = "";
String line;
while ((line=bf.readLine())!=null) {
outStr += line;
}
System.out.println("Output String lenght : " + outStr.length());
return outStr;
}
Je ne comprenais toujours pas comment résoudre ce problème !!!
C'est à cause de
String outStr = obj.toString("UTF-8");
Envoyez le byte[]
que vous pouvez obtenir de votre ByteArrayOutputStream
et utilisez-le tel quel dans votre ByteArrayInputStream
pour construire votre GZIPInputStream
. Vous trouverez ci-dessous les modifications à apporter à votre code.
byte[] compressed = compress(string); //In the main method
public static byte[] compress(String str) throws Exception {
...
...
return obj.toByteArray();
}
public static String decompress(byte[] bytes) throws Exception {
...
GZIPInputStream gis = new GZIPInputStream(new ByteArrayInputStream(bytes));
...
}
La réponse ci-dessus résout notre problème mais en plus de cela. si nous essayons de décompresser un octet [] ..__ non compressé ("pas un format Zip"), nous aurons un message d’exception "Pas au format GZIP".
Pour résoudre ce problème, nous pouvons ajouter du code d'addition dans notre classe.
public static boolean isCompressed(final byte[] compressed) {
return (compressed[0] == (byte) (GZIPInputStream.GZIP_MAGIC)) && (compressed[1] == (byte) (GZIPInputStream.GZIP_MAGIC >> 8));
}
Ma classe de compression complète avec compression/décompression ressemblerait à ceci:
import Java.io.BufferedReader;
import Java.io.ByteArrayInputStream;
import Java.io.ByteArrayOutputStream;
import Java.io.IOException;
import Java.io.InputStreamReader;
import Java.util.Zip.GZIPInputStream;
import Java.util.Zip.GZIPOutputStream;
public class GZIPCompression {
public static byte[] compress(final String str) throws IOException {
if ((str == null) || (str.length() == 0)) {
return null;
}
ByteArrayOutputStream obj = new ByteArrayOutputStream();
GZIPOutputStream gzip = new GZIPOutputStream(obj);
gzip.write(str.getBytes("UTF-8"));
gzip.flush();
gzip.close();
return obj.toByteArray();
}
public static String decompress(final byte[] compressed) throws IOException {
final StringBuilder outStr = new StringBuilder();
if ((compressed == null) || (compressed.length == 0)) {
return "";
}
if (isCompressed(compressed)) {
final GZIPInputStream gis = new GZIPInputStream(new ByteArrayInputStream(compressed));
final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(gis, "UTF-8"));
String line;
while ((line = bufferedReader.readLine()) != null) {
outStr.append(line);
}
} else {
outStr.append(compressed);
}
return outStr.toString();
}
public static boolean isCompressed(final byte[] compressed) {
return (compressed[0] == (byte) (GZIPInputStream.GZIP_MAGIC)) && (compressed[1] == (byte) (GZIPInputStream.GZIP_MAGIC >> 8));
}
}
Si vous avez besoin de transférer le contenu compressé via le réseau ou de le stocker sous forme de texte, vous devez utiliser un encodeur Base64 (tel que le codec Apache commons Base64) pour convertir le tableau d'octets en chaîne Base64 et client distant. Vous avez trouvé un exemple dans Utilisez Zip Stream et Base64 Encoder pour compresser des données de grande taille !
Le problème est cette ligne:
String outStr = obj.toString("UTF-8");
Le tableau d'octets obj
contient des données binaires arbitraires. Vous ne pouvez pas "décoder" des données binaires arbitraires comme s'il s'agissait d'UTF-8. Si vous essayez, vous obtiendrez une chaîne qui ne peut pas ensuite être "encodée" en octets. Ou du moins, les octets que vous obtiendrez seront différents de ceux avec lesquels vous avez commencé ... dans la mesure où ils ne sont plus un flux GZIP valide.
Le correctif consiste à stocker ou à transmettre le contenu du tableau d'octets tel quel. N'essayez pas de le convertir en chaîne. Ce sont des données binaires, pas du texte.
Un autre exemple de compression et décompression correcte:
@Slf4j
public class GZIPCompression {
public static byte[] compress(final String stringToCompress) {
if (isNull(stringToCompress) || stringToCompress.length() == 0) {
return null;
}
try (final ByteArrayOutputStream baos = new ByteArrayOutputStream();
final GZIPOutputStream gzipOutput = new GZIPOutputStream(baos)) {
gzipOutput.write(stringToCompress.getBytes(UTF_8));
gzipOutput.finish();
return baos.toByteArray();
} catch (IOException e) {
throw new UncheckedIOException("Error while compression!", e);
}
}
public static String decompress(final byte[] compressed) {
if (isNull(compressed) || compressed.length == 0) {
return null;
}
try (final GZIPInputStream gzipInput = new GZIPInputStream(new ByteArrayInputStream(compressed));
final StringWriter stringWriter = new StringWriter()) {
IOUtils.copy(gzipInput, stringWriter, UTF_8);
return stringWriter.toString();
} catch (IOException e) {
throw new UncheckedIOException("Error while decompression!", e);
}
}
}
Vous ne pouvez pas convertir les données binaires en String. En tant que solution, vous pouvez encoder des données binaires puis les convertir en chaîne. Par exemple, regardez ceci Comment convertissez-vous des données binaires en chaînes et en Java?