2010-01-14 9 views
23

J'essaye d'écrire une fonction qui acceptera un InputStream avec les données de dossier compressées et renverrait un autre InputStream avec des données décompressées.Dézipper un fichier d'InputStream et retourner un autre InputStream

Le fichier compressé ne contient un seul fichier et donc il n'y a pas besoin de créer des répertoires, etc ...

J'ai essayé de regarder ZipInputStream et d'autres, mais je suis confus par tant de différents types de cours d'eau Java.

+1

Qu'avez-vous déjà essayé? S'il vous plaît ajouter un exemple de code. –

Répondre

40

Concepts

GZipinputstream est pour les flux (ou fichiers) zipée gzip (extension ".gz"). Il n'a aucune information d'en-tête.

GZipInputStream is for [zippeddata] 

Si vous avez un vrai fichier zip, vous devez utilisateur ZipFile pour ouvrir le fichier, demandez la liste des fichiers (un dans votre exemple) et demandez le flux d'entrée décompressé.

ZipFile is for a file with [header information + zippeddata] 

Votre méthode, si vous avez le fichier, serait quelque chose comme:

// ITS PSEUDOCODE!! 

private InputStream extractOnlyFile(String path) { 
    ZipFile zf = new ZipFile(path); 
    Enumeration e = zf.entries(); 
    ZipEntry entry = (ZipEntry) e.nextElement(); // your only file 
    return zf.getInputStream(entry); 
} 

La lecture d'un InputStream avec le contenu d'un fichier .zip

Ok, si vous avez un InputStream que vous pouvez utiliser (comme le dit @cletus) ZipInputStream. Il lit un flux incluant les données d'en-tête.

ZipInputStream is for a stream with [header information + zippeddata] 

Important: si vous avez le fichier dans votre PC, vous pouvez utiliser ZipFile classe pour accéder au hasard

Ceci est un exemple de la lecture d'un fichier zip à travers un InputStream:

import java.io.FileInputStream; 
import java.util.zip.ZipEntry; 
import java.util.zip.ZipInputStream; 


public class Main { 
    public static void main(String[] args) throws Exception 
    { 
     FileInputStream fis = new FileInputStream("c:/inas400.zip"); 

     // this is where you start, with an InputStream containing the bytes from the zip file 
     ZipInputStream zis = new ZipInputStream(fis); 
     ZipEntry entry; 
      // while there are entries I process them 
     while ((entry = zis.getNextEntry()) != null) 
     { 
      System.out.println("entry: " + entry.getName() + ", " + entry.getSize()); 
        // consume all the data from this entry 
      while (zis.available() > 0) 
       zis.read(); 
        // I could close the entry, but getNextEntry does it automatically 
        // zis.closeEntry() 
     } 
    } 
} 
+0

J'ai corrigé le code, le ZipInputStream a dû envelopper le flux d'entrée d'origine :). Merci! – helios

+0

Helios: zipinput.getNextEntry() retournera un objet ZipEntry. Comment puis-je le convertir en flux? –

+0

zipinputstream représente un flux d'entrée des données décompressées du fichier. C'est pourquoi je retourne "zipinput". Mais il faut lire les en-têtes et positionner au début des données zippées actuelles pour commencer. C'est pourquoi j'appelle d'abord "getnextentry". Pour que le zipinputstream lise cet en-tête et se prépare à décompresser son entrée (et bien sûr, à connaître le nom du fichier compressé :). – helios

2

À moins que je ne manque quelque chose, vous devriez absolument essayer et obtenir ZipInputStream au travail et il n'y a aucune raison pour laquelle il ne devrait pas (je l'ai certainement utilisé à plusieurs reprises).

Ce que vous devez faire est d'essayer de faire fonctionner ZipInputStream et si vous ne pouvez pas, postez le code et nous vous aiderons avec tous les problèmes que vous rencontrez. Cependant, quoi que vous fassiez, n'essayez pas de réinventer ses fonctionnalités.

+2

il semble avoir essayé cela et n'a pas compris comment l'utiliser. – Bozho

+7

Pour être juste, 'java.util.zip' est une API assez désagréable – skaffman

6

Si vous pouvez modifier les données d'entrée, je vous suggère d'utiliser GZIPInputStream.

GZipInputStream est différent de ZipInputStream puisque vous n'avez qu'une seule donnée à l'intérieur. Donc, le flux d'entrée entier représente le fichier entier. Dans ZipInputStream le flux entier contient également la structure du fichier (s) à l'intérieur, ce qui peut être beaucoup.

+1

Le fichier n'est pas sous mon contrôle. C'est un fichier que je télécharge depuis un serveur. J'avais l'habitude de l'enregistrer sur le disque puis de le décompresser, mais maintenant je pense à le décompresser en mémoire. –

+0

Ce qui importe n'est pas vraiment si les octets proviennent d'une socket réseau ou d'un fichier. La distinction à faire est entre une archive zip et un blob de données compressées. Si vous écrivez et lisez les données, peut-être que vous ne vous soucieriez pas vraiment de l'archive avec ses métadonnées, et alors GZipStream serait le choix. Vous recevez clairement une archive (ou bien l'enregistrez dans un fichier et la décompresser échouerait probablement, au moins si vous décompressez en exécutant un programme de décompression "standard"). Vous pouvez en effet le décompresser en mémoire, en utilisant ZipInputStream. –

2

Il est sur la syntaxe scala:

def unzipByteArray(input: Array[Byte]): String = { 
    val zipInputStream = new ZipInputStream(new ByteArrayInputStream(input)) 
    val entry = zipInputStream.getNextEntry 
    IOUtils.toString(zipInputStream, StandardCharsets.UTF_8) 
} 
Questions connexes