GZIPInputStream Zeile für Zeile lesen


84

Ich habe eine Datei im GZ-Format. Die Java-Klasse zum Lesen dieser Datei ist GZIPInputStream. Diese Klasse erweitert jedoch nicht die BufferedReader-Klasse von Java. Infolgedessen kann ich die Datei nicht zeilenweise lesen. Ich brauche so etwas

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

Ich möchte meine Klasse erstellen, die die Java-Klasse Reader oder BufferedReader erweitert, und GZIPInputStream als eine ihrer Variablen verwenden.

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

}

Aber das funktioniert nicht, wenn ich benutze

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

Kann jemand raten, wie es weitergeht ..


Schauen Sie sich diesen Link an stackoverflow.com/q/6717165/779408 . Dort ist eine Komprimierungs- und Dekomprimierungsmethode dargestellt.
Bobs

1
Für die Liebe zu allem, was auf dieser Welt gut und richtig ist, und für die Vernunft aller Entwickler, die auch nur aus der Ferne lohnenden Code schreiben. Er ist die einzige Antwort, die darauf hinweist, was mich zum Weinen bringt.
James

Antworten:


141

Die Grundausstattung der Dekorateure sieht folgendermaßen aus:

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

Das Hauptproblem in diesem Snippet ist der Wert von encoding. Dies ist die Zeichenkodierung des Textes in der Datei. Ist es "US-ASCII", "UTF-8", "SHIFT-JIS", "ISO-8859-9", ...? Es gibt Hunderte von Möglichkeiten, und die richtige Auswahl kann normalerweise nicht aus der Datei selbst ermittelt werden. Es muss über einen Out-of-Band-Kanal angegeben werden.

Zum Beispiel ist es vielleicht die Plattformvorgabe. In einer vernetzten Umgebung ist dies jedoch äußerst fragil. Der Computer, der die Datei geschrieben hat, befindet sich möglicherweise in der benachbarten Kabine, hat jedoch eine andere Standarddateicodierung.

Die meisten Netzwerkprotokolle verwenden einen Header oder andere Metadaten, um die Zeichencodierung explizit zu notieren.

In diesem Fall geht aus der Dateierweiterung hervor, dass der Inhalt XML ist. XML enthält zu diesem Zweck das Attribut "encoding" in der XML-Deklaration. Darüber hinaus sollte XML wirklich mit einem XML-Parser verarbeitet werden, nicht als Text. Das zeilenweise Lesen von XML scheint ein fragiler Sonderfall zu sein.

Wenn die Codierung nicht explizit angegeben wird, verstößt dies gegen das zweite Gebot. Verwenden Sie die Standardcodierung auf eigene Gefahr!


1
danke, es hat funktioniert ... Es ist jedoch kein Leseschritt erforderlich. Wir können ihn auch als GZIPInputStream schreiben. gzip = new GZIPInputStream (neuer FileInputStream ("F: /gawiki-20090614-stub-meta-history.xml.gz") )); BufferedReader br = neuer BufferedReader (neuer InputStreamReader (gzip));
Kapil D

12
@KapilD Es macht mich traurig, dass Sie seinen Standpunkt zur Kodierung völlig verfehlt haben ... wie Ihr Kommentar und das Beispiel in Ihrem Kommentar zeigen. Lesen Sie Ericksons Antwort noch einmal durch ... vielleicht 30 Mal.
James

Woher kennt der Befehl gzip die Codierung? Ich möchte viele Dateien von vielen Linux / Unix-Servern aus der ganzen Welt lesen ... also möchte ich sicherstellen, dass ich das richtig mache ... Der Beitrag erwähnt, dass die Codierung normalerweise nicht von der Datei selbst bestimmt werden kann ... aber der Befehl gzip -d scheint für jede Datei ohne separate Eingabe zu funktionieren ... (es ist das, was ich jetzt verwende, aber umgehen möchte), also überlege ich mir, ob ich nur herausfinden kann, was gzip tut, um die Codierung zu kennen, ich kann das gleiche tun. Irgendwelche Gedanken / Vorschläge kann mich jemand in die richtige Richtung weisen?
Glyphx

@glyphx Deine Frage ist nicht klar. Meinen Sie damit, wie Sie eine gzip-Datei erkennen können, wenn keine externe Aussage zum Inhaltstyp vorliegt? Ein Hinweis ist die Dateierweiterung, ein anderer ist das Vorhandensein der magischen Zahl 0x1F8B im Dateikopf. Sie können jedoch nicht wissen, dass eine Datei eine gültige gzip-Datei ist, bis Sie das Ganze tatsächlich verarbeitet haben.
erickson

1
Um klar zu sein, ich weiß, dass diese Dateien gzip-Dateien sind. Und die komprimierten Dateien sind alle textbasierte Dateien, wie z. B. CSV- und Pipe-Delim-Dateien. Ich möchte nur in der Lage sein, diese Dateien Zeile für Zeile direkt mit Java zu lesen. Ich kann sie gzip -d und dann Zeile für Zeile lesen kein Problem. Ich war nur verwirrt in Ihren Kommentaren darüber, dass Sie die Codierung angeben müssen ... Ich würde denken, dass die meisten Dateien ASCII sind ... aber einige haben möglicherweise asiatische Zeichen, also vielleicht UTF-8? Ich möchte nur sicherstellen, dass ich das richtig mache ... Ist das klarer? Vielen Dank!
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();


Ihre Antwort ist großartig. Kurz und prägnant. Die Antwort von erickson ist jedoch detaillierter.
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);

2

Sie können die folgende Methode in einer util-Klasse verwenden und sie bei Bedarf verwenden ...

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

1

hier ist mit einer Zeile

try (BufferedReader br = new BufferedReader(
        new InputStreamReader(
           new GZIPInputStream(
              new FileInputStream(
                 "F:/gawiki-20090614-stub-meta-history.xml.gz"))))) 
     {br.readLine();}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.