GZIPInputStream lectura línea por línea

85

Tengo un archivo en formato .gz. La clase java para leer este archivo es GZIPInputStream. Sin embargo, esta clase no amplía la clase BufferedReader de java. Como resultado, no puedo leer el archivo línea por línea. necesito algo como esto

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

Pensé en crear mi clase que extiende la clase Reader o BufferedReader de Java y uso GZIPInputStream como una de sus 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);
    }

}

Pero esto no funciona cuando uso

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

¿Alguien puede aconsejarnos cómo proceder?

Kapil D
fuente
mire este enlace stackoverflow.com/q/6717165/779408 . Allí se representa un método de compresión y descompresión.
Bobs
1
Por el amor de todo lo que es bueno y correcto en este mundo y por la cordura de cualquier desarrollador que escriba un código que valga la pena, aunque sea remotamente ... ¡TENGA EN CUENTA LA CODIFICACIÓN COMO @erickson SEÑALA! Él es la única respuesta que señala esto, lo que me da ganas de llorar.
James

Respuestas:

143

La configuración básica de los decoradores es la siguiente:

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

La cuestión clave en este fragmento es el valor de encoding. Esta es la codificación de caracteres del texto en el archivo. ¿Es "US-ASCII", "UTF-8", "SHIFT-JIS", "ISO-8859-9",…? hay cientos de posibilidades y, por lo general, la elección correcta no se puede determinar a partir del archivo en sí. Debe especificarse a través de algún canal fuera de banda.

Por ejemplo, tal vez sea la plataforma predeterminada. En un entorno en red, sin embargo, esto es extremadamente frágil. La máquina que escribió el archivo puede ubicarse en el cubículo vecino, pero tiene una codificación de archivo predeterminada diferente.

La mayoría de los protocolos de red utilizan un encabezado u otros metadatos para anotar explícitamente la codificación de caracteres.

En este caso, a partir de la extensión del archivo, parece que el contenido es XML. XML incluye el atributo "codificación" en la declaración XML para este propósito. Además, XML realmente debería procesarse con un analizador XML, no como texto. Leer XML línea por línea parece un caso especial y frágil.

No especificar explícitamente la codificación va en contra del segundo mandamiento. ¡Utilice la codificación predeterminada bajo su responsabilidad!

erickson
fuente
1
gracias funcionó ... Sin embargo, no es necesario el paso del lector ... también podemos escribirlo como GZIPInputStream gzip = new GZIPInputStream (new FileInputStream ("F: /gawiki-20090614-stub-meta-history.xml.gz" )); BufferedReader br = new BufferedReader (nuevo InputStreamReader (gzip));
Kapil D
12
@KapilD me entristece que hayas perdido completamente su punto sobre la codificación ... como se muestra en tu comentario y el ejemplo en tu comentario. Vuelva a leer la respuesta de Erickson ... tal vez 30 veces.
James
¿Cómo conoce el comando gzip la codificación? Quiero leer muchos archivos de muchos servidores linux / unix de todo el mundo ... así que quiero asegurarme de hacerlo bien ... La publicación menciona que la codificación generalmente no puede ser determinada por el archivo en sí ... pero el comando gzip -d parece funcionar en cualquier archivo sin una entrada separada ... (es lo que uso ahora pero quiero eludir) así que me imagino que si puedo averiguar qué hace gzip para conocer la codificación, puede hacer lo mismo. ¿Alguna idea / sugerencia puede alguien señalarme en la dirección correcta?
glifo
@glyphx Tu pregunta no está clara. ¿Quiere decir cómo puede reconocer un archivo gzip en ausencia de alguna afirmación externa sobre el tipo de contenido? Una pista es la extensión del archivo, otra es la presencia del número mágico 0x1F8B en el encabezado del archivo. Sin embargo, no puede saber que un archivo es un archivo gzip válido hasta que lo procese todo.
erickson
1
Para ser claros, sé que estos archivos son archivos gzip. Y los archivos comprimidos con gzip son todos archivos basados ​​en texto, como csv y archivos de delimitación de tuberías. Solo quiero poder leer estos archivos directamente con Java línea por línea. Puedo gzip -d y luego leerlos línea por línea sin problema. Estaba confundido en sus comentarios acerca de tener que especificar la codificación ... Creo que la mayoría de los archivos son ASCII ... pero algunos pueden tener caracteres asiáticos, ¿tal vez UTF-8? Solo quiero asegurarme de hacer esto correctamente ... ¿Está más claro? ¡Gracias!
glifo
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
fuente
Tu respuesta es genial. Breve y concisa. Sin embargo, la respuesta de Erickson es más detallada.
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
fuente
2

Puede utilizar el siguiente método en una clase util y utilizarlo siempre que sea necesario ...

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
fuente
1

aquí está con una línea

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