GZIPInputStream odczytuje wiersz po wierszu

85

Mam plik w formacie .gz. Klasą Java do odczytu tego pliku jest GZIPInputStream. Jednak ta klasa nie rozszerza klasy BufferedReader języka java. W rezultacie nie mogę odczytać pliku wiersz po wierszu. Potrzebuję czegoś takiego

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

Pomyślałem o stworzeniu mojej klasy, która rozszerza klasę Reader lub BufferedReader java i używa GZIPInputStream jako jednej z jej zmiennych.

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

}

Ale to nie działa, gdy używam

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

Czy ktoś może doradzić, jak postępować ...

Kapil D
źródło
spójrz na ten link stackoverflow.com/q/6717165/779408 . Przedstawiona jest tam metoda kompresji i dekompresji.
Bobs
1
Z miłości do wszystkiego, co jest dobre i słuszne na tym świecie, oraz dla zdrowego rozsądku programistów, którzy piszą choćby zdalnie wartościowy kod… UWAŻAJ NA KODOWANIE, JAK @erickson WSKAZUJE! On jest jedyną odpowiedzią, która na to wskazuje, przez co mam ochotę płakać.
James,

Odpowiedzi:

143

Podstawowa konfiguracja dekoratorów wygląda następująco:

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

Kluczową kwestią w tym fragmencie jest wartość encoding. To jest kodowanie znaków tekstu w pliku. Czy jest to „US-ASCII”, „UTF-8”, „SHIFT-JIS”, „ISO-8859-9”,…? możliwości są setki, a właściwego wyboru zwykle nie można określić na podstawie samego pliku. Musi być określony przez jakiś kanał pozapasmowy.

Na przykład, może jest to domyślna platforma. Jednak w środowisku sieciowym jest to niezwykle delikatne. Maszyna, która zapisała plik, może znajdować się w sąsiednim boksie, ale ma inne domyślne kodowanie pliku.

Większość protokołów sieciowych używa nagłówka lub innych metadanych, aby wyraźnie zaznaczyć kodowanie znaków.

W tym przypadku z rozszerzenia pliku wynika, że ​​zawartość to XML. XML zawiera w tym celu atrybut „encoding” w deklaracji XML. Ponadto XML powinien być naprawdę przetwarzany za pomocą parsera XML, a nie jako tekst. Czytanie XML wiersz po wierszu wydaje się delikatnym, specjalnym przypadkiem.

Brak wyraźnego określenia kodowania jest sprzeczny z drugim przykazaniem. Używaj domyślnego kodowania na własne ryzyko!

erickson
źródło
1
dzięki, że zadziałało ... Jednak nie ma potrzeby wykonywania kroku czytnika .. możemy również zapisać go jako GZIPInputStream gzip = new GZIPInputStream (new FileInputStream ("F: /gawiki-20090614-stub-meta-history.xml.gz" )); BufferedReader br = new BufferedReader (new InputStreamReader (gzip));
Kapil D
12
@KapilD zasmuca mnie, że całkowicie przegapiłeś jego punkt widzenia na temat kodowania ... jak pokazuje Twój komentarz i przykład w Twoim komentarzu. Przeczytaj ponownie odpowiedź Ericksona ... może 30 razy.
James,
Skąd polecenie gzip zna kodowanie? Chcę czytać wiele plików z wielu serwerów linux / unix z całego świata ... więc chcę się upewnić, że robię to dobrze ... We wpisie wspomniano o kodowaniu zwykle nie może być określone przez sam plik ... ale polecenie gzip -d wydaje się działać na każdym pliku bez oddzielnych danych wejściowych ... (tego właśnie używam teraz, ale chcę obejść), więc zastanawiam się, czy mogę po prostu dowiedzieć się, co robi gzip, aby poznać kodowanie, ja może zrobić to samo. Jakieś przemyślenia / sugestie, czy ktoś może wskazać mi właściwy kierunek?
glifx
@glyphx Twoje pytanie nie jest jasne. Czy masz na myśli, jak rozpoznać plik gzip w przypadku braku zewnętrznego potwierdzenia o typie zawartości? Jedna wskazówka to rozszerzenie pliku, druga to obecność magicznej liczby 0x1F8B w nagłówku pliku. Jednak nie możesz wiedzieć, że plik jest prawidłowym plikiem gzip, dopóki nie przetworzysz całości.
erickson,
1
Żeby było jasne, wiem, że te pliki to pliki gzip. Wszystkie pliki spakowane gzip są plikami tekstowymi, takimi jak pliki CSV i pliki rozdzielające potoki. Chcę tylko móc czytać te pliki bezpośrednio w java wiersz po wierszu. Mogę je zgzip -d, a następnie czytać wiersz po wierszu bez problemu. W twoich komentarzach byłem po prostu zdezorientowany, że muszę określić kodowanie ... Myślę, że większość plików to ASCII ... ale niektóre mogą mieć znaki azjatyckie, więc może UTF-8? Chcę się tylko upewnić, że robię to poprawnie ... Czy to jest jaśniejsze? Dzięki!
glifx
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
źródło
Twoja odpowiedź jest świetna. Krótka i zwięzła… Jednak odpowiedź Ericksona jest bardziej szczegółowa.
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
źródło
2

Możesz użyć następującej metody w klasie util i używać jej w razie potrzeby ...

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
źródło
1

tutaj jest z jedną linią

try (BufferedReader br = new BufferedReader(
        new InputStreamReader(
           new GZIPInputStream(
              new FileInputStream(
                 "F:/gawiki-20090614-stub-meta-history.xml.gz"))))) 
     {br.readLine();}
Pogromca
źródło