GZIPInputStream lecture ligne par ligne

85

J'ai un fichier au format .gz. La classe java pour lire ce fichier est GZIPInputStream. Cependant, cette classe n'étend pas la classe BufferedReader de java. Par conséquent, je ne peux pas lire le fichier ligne par ligne. J'ai besoin de quelque chose comme ça

reader  = new MyGZInputStream( some constructor of GZInputStream) 
reader.readLine()...

J'ai pensé à créer ma classe qui étend la classe Reader ou BufferedReader de java et utilise GZIPInputStream comme l'une de ses variables.

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.Reader;
import java.util.zip.GZIPInputStream;

public class MyGZFilReader extends Reader {

    private GZIPInputStream gzipInputStream = null;
    char[] buf = new char[1024];

    @Override
    public void close() throws IOException {
        gzipInputStream.close();
    }

    public MyGZFilReader(String filename)
               throws FileNotFoundException, IOException {
        gzipInputStream = new GZIPInputStream(new FileInputStream(filename));
    }

    @Override
    public int read(char[] cbuf, int off, int len) throws IOException {
        // TODO Auto-generated method stub
        return gzipInputStream.read((byte[])buf, off, len);
    }

}

Mais cela ne fonctionne pas quand j'utilise

BufferedReader in = new BufferedReader(
    new MyGZFilReader("F:/gawiki-20090614-stub-meta-history.xml.gz"));
System.out.println(in.readLine());

Quelqu'un peut-il conseiller comment procéder ...

Kapil D
la source
regardez ce lien stackoverflow.com/q/6717165/779408 . Une méthode de compression et décompression y est représentée.
Bobs
1
Pour l'amour de tout ce qui est bon et juste dans ce monde et pour la santé mentale de tous les développeurs qui écrivent même à distance du code utile ..... SOYEZ CONSCIENT DE L'ENCODAGE COMME @erickson POINTS OUT! Il est la seule réponse qui le souligne, ce qui me donne envie de pleurer.
James

Réponses:

143

La configuration de base des décorateurs est la suivante:

InputStream fileStream = new FileInputStream(filename);
InputStream gzipStream = new GZIPInputStream(fileStream);
Reader decoder = new InputStreamReader(gzipStream, encoding);
BufferedReader buffered = new BufferedReader(decoder);

Le problème clé de cet extrait de code est la valeur de encoding. Il s'agit du codage des caractères du texte du fichier. Est-ce "US-ASCII", "UTF-8", "SHIFT-JIS", "ISO-8859-9",…? il existe des centaines de possibilités et le choix correct ne peut généralement pas être déterminé à partir du fichier lui-même. Il doit être spécifié via un canal hors bande.

Par exemple, c'est peut-être la plate-forme par défaut. Dans un environnement en réseau, cependant, cela est extrêmement fragile. La machine qui a écrit le fichier peut se trouver dans la cellule voisine, mais avoir un codage de fichier par défaut différent.

La plupart des protocoles réseau utilisent un en-tête ou d'autres métadonnées pour noter explicitement le codage des caractères.

Dans ce cas, il ressort de l'extension de fichier que le contenu est XML. XML inclut l'attribut "encoding" dans la déclaration XML à cet effet. De plus, XML devrait vraiment être traité avec un analyseur XML, pas sous forme de texte. La lecture de XML ligne par ligne semble être un cas particulier et fragile.

Ne pas spécifier explicitement le codage est contraire au deuxième commandement. Utilisez l'encodage par défaut à vos risques et périls!

Erickson
la source
1
merci cela a fonctionné ... Cependant, il n'y a pas besoin d'étape de lecture .. nous pouvons aussi l'écrire comme GZIPInputStream gzip = new GZIPInputStream (new FileInputStream ("F: /gawiki-20090614-stub-meta-history.xml.gz" )); BufferedReader br = nouveau BufferedReader (nouveau InputStreamReader (gzip));
Kapil D
12
@KapilD cela me rend triste que vous ayez complètement manqué son point sur l'encodage ... comme le montrent votre commentaire et l'exemple dans votre commentaire. Relisez la réponse d'Erickson ... peut-être 30 fois.
James
Comment la commande gzip connaît-elle le codage? Je veux lire beaucoup de fichiers à partir de nombreux serveurs Linux / Unix du monde entier ... donc je veux m'assurer de le faire correctement ... Le message mentionne que l'encodage ne peut généralement pas être déterminé par le fichier lui-même ... mais la commande gzip -d semble fonctionner sur n'importe quel fichier sans entrée séparée ... (c'est ce que j'utilise maintenant mais que je veux contourner) donc je suppose que si je peux simplement comprendre ce que fait gzip pour connaître l'encodage, je peut faire la même chose. Des pensées / suggestions peuvent-elles m'indiquer dans la bonne direction?
glyphx
@glyphx Votre question n'est pas claire. Voulez-vous dire comment pouvez-vous reconnaître un fichier gzip en l'absence d'une assertion externe sur le type de contenu? Un indice est l'extension du fichier, un autre est la présence du nombre magique 0x1F8B dans l'en-tête du fichier. Cependant, vous ne pouvez pas savoir qu'un fichier est un fichier gzip valide tant que vous ne l'avez pas réellement traité.
erickson
1
Pour être clair, je sais que ces fichiers sont des fichiers gzip. Et les fichiers gzippés sont tous des fichiers texte, comme les fichiers csv et pipe delim. Je veux juste pouvoir lire ces fichiers directement avec java ligne par ligne. Je peux les gzip -d et les lire ligne par ligne sans problème. J'étais juste confus dans vos commentaires sur le fait de devoir spécifier l'encodage ... Je pense que la plupart des fichiers sont ASCII ... mais certains peuvent avoir des caractères asiatiques, alors peut-être UTF-8? Je veux juste m'assurer de le faire correctement ... Est-ce que c'est plus clair? Merci!
glyphx
44
GZIPInputStream gzip = new GZIPInputStream(new FileInputStream("F:/gawiki-20090614-stub-meta-history.xml.gz"));
BufferedReader br = new BufferedReader(new InputStreamReader(gzip));
br.readLine();

ChssPly76
la source
Votre réponse est excellente. Bref et concis. Cependant, la réponse d'Erickson est plus détaillée.
Kapil D
3
BufferedReader in = new BufferedReader(new InputStreamReader(
        new GZIPInputStream(new FileInputStream("F:/gawiki-20090614-stub-meta-history.xml.gz"))));

String content;

while ((content = in.readLine()) != null)

   System.out.println(content);
Arumugam Mathiazhagan
la source
2

Vous pouvez utiliser la méthode suivante dans une classe util et l'utiliser chaque fois que nécessaire ...

public static List<String> readLinesFromGZ(String filePath) {
    List<String> lines = new ArrayList<>();
    File file = new File(filePath);

    try (GZIPInputStream gzip = new GZIPInputStream(new FileInputStream(file));
            BufferedReader br = new BufferedReader(new InputStreamReader(gzip));) {
        String line = null;
        while ((line = br.readLine()) != null) {
            lines.add(line);
        }
    } catch (FileNotFoundException e) {
        e.printStackTrace(System.err);
    } catch (IOException e) {
        e.printStackTrace(System.err);
    }
    return lines;
}
Memin
la source
1

voici avec une ligne

try (BufferedReader br = new BufferedReader(
        new InputStreamReader(
           new GZIPInputStream(
              new FileInputStream(
                 "F:/gawiki-20090614-stub-meta-history.xml.gz"))))) 
     {br.readLine();}
Dompteur
la source