Come faccio ad avere l'InputStream dei dati decompressi da un InputStream dei dati compressi con gzip?
-
20-09-2019 - |
Domanda
io chiamo un servizio che restituisce un file zippato. Ho i dati come un InputStream (per gentile concessione di javax.activation.DataHandler.getInputStream();
) dalla risposta.
Quello che vorrei fare è, senza scrivere nulla sul disco, ottenere un InputStream dei dati decompressi nel file che è in archivio. Il file compresso in questo caso è un documento XML che sto cercando di unmarshalling utilizzando javax.xml.bind.Unmarshaller
che prende un InputStream.
Al momento sto cercando di scrivere l'InputStream ad un OutputStream (la decompressione dei dati) e poi ti bisogno di scrivere di nuovo a un InputStream. Non funziona eppure così ho pensato di vedere se c'era un (spero così) approccio migliore.
Posso scrivere l'InputStream iniziale per disco e ottenere un file gz, e quindi leggere il file, ottenere il file compresso fuori di esso e passare da lì, ma preferirei tenere tutto in memoria è possibile.
Aggiornamento 1: Qui è il mio attuale (che non funziona - ottenere un'eccezione "Not in formato gzip"):
ByteArrayInputStream xmlInput = null;
try {
InputStream in = dh.getInputStream(); //dh is a javax.activation.DataHandler
BufferedInputStream bis = new BufferedInputStream(in);
ByteArrayOutputStream bo = new ByteArrayOutputStream();
int bytes_read = 0;
byte[] dataBuf = new byte[4096];
while ((bytes_read = bis.read(dataBuf)) != -1) {
bo.write(dataBuf, 0, bytes_read);
}
ByteArrayInputStream bin = new ByteArrayInputStream(bo.toByteArray());
GZIPInputStream gzipInput = new GZIPInputStream(bin);
ByteArrayOutputStream out = new ByteArrayOutputStream();
dataBuf = new byte[4096];;
bytes_read = 0;
while ((bytes_read = gzipInput.read(dataBuf)) > 0) {
out.write(dataBuf, 0, bytes_read);
}
xmlInput = new ByteArrayInputStream(out.toByteArray());
Se invece di scrivere a un ByteArrayOutputStream scrivo ad un FileOutputStream la prima volta intorno ho un file compresso (che posso aprire manualmente per ottenere il file XML all'interno) e il servizio (eBay) dice che dovrebbe essere un file gzip quindi non so perché ricevo un errore "Not in GZIP formato".
Aggiornamento 2: ho provato qualcosa di diverso - stesso errore ( "Non nel formato gzip"). Wow, ho solo cercato di porre fine a questa parentesi con un punto e virgola. In ogni modo, ecco il mio secondo tentativo, che ancora non funziona:
ByteArrayInputStream xmlInput = null;
try {
GZIPInputStream gzipInput = new GZIPInputStream(dh.getInputStream());
ByteArrayOutputStream bo = new ByteArrayOutputStream();
int bytes_read = 0;
byte[] dataBuf = new byte[4096];
while ((bytes_read = gzipInput.read(dataBuf)) != -1) {
bo.write(dataBuf, 0, bytes_read);
}
xmlInput = new ByteArrayInputStream(bo.toByteArray());
Soluzione
Il seguente codice dovrebbe funzionare. Tenete a mente che dovrete gestire le eccezioni in modo corretto.
OutputStream out = null;
InputStream in = null;
try {
out = /* some output stream */;
in = new java.util.GZIPInputStream(/*some stream*/);
byte[] buffer = new byte[4096];
int c = 0;
while (( c = in.read(buffer, 0, 4096)) > 0) {
out.write(buffer, 0, c);
}
} finally {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
}
Altri suggerimenti
Decora il flusso di input con un GZIPInputStream
.
InputStream decompressed = new GZIPInputStream(compressed);
Date un'occhiata a GZIPInputStream. Ecco un esempio ; la classe gestisce questo molto trasparente, è quasi nessun lavoro da utilizzare.