GZIPInputStream逐行读取

96

我有一个以 .gz 格式存储的文件。用于读取该文件的 Java 类是 GZIPInputStream。 然而,该类并没有扩展 Java 的 BufferedReader 类。因此,我无法按行读取文件内容。我需要像下面这样的东西:

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

我想创建一个继承Java的Reader或BufferedReader类并使用GZIPInputStream作为其中一个变量的类。

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

}

但是,当我使用它时,它不起作用。

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

请问有人能指导一下如何处理吗?


请查看此链接https://dev59.com/oGw15IYBdhLWcg3wSJo3。其中提供了一种压缩和解压缩的方法。 - Bobs
1
为了这个世界上所有的善良和正义,以及撰写出任何值得一提的代码的开发者们的理智,请注意编码问题......就像@erickson所指出的那样!他是唯一提到这一点的答案,这让我想哭。 - James
5个回答

155

装饰器的基本设置如下:

InputStream fileStream = new FileInputStream(filename);
InputStream gzipStream = new GZIPInputStream(fileStream);
Reader decoder = new InputStreamReader(gzipStream, encoding);
BufferedReader buffered = new BufferedReader(decoder);
这段代码片段的关键问题在于encoding的值。它是文件中文本的字符编码。它可以是"US-ASCII"、"UTF-8"、"SHIFT-JIS"、"ISO-8859-9"等数百种可能性,通常无法从文件本身确定正确的选择,必须通过一些外部渠道来指定。
例如,也许它是平台默认设置。然而,在网络环境中,这非常不稳定。编写文件的机器可能坐在相邻的隔间里,但有不同的默认文件编码。
大多数网络协议使用标头或其他元数据来明确注明字符编码。
在这种情况下,从文件扩展名来看,内容似乎是XML。XML在XML声明中包含"encoding"属性,用于此目的。此外,XML应该使用XML解析器处理,而不是作为文本逐行读取。逐行读取XML似乎是一个脆弱的特例。
未明确指定编码会违反第二条戒律自讨苦吃,不要使用默认编码!

1
谢谢,它起作用了...然而,读取步骤是不必要的..我们也可以这样写: GZIPInputStream gzip = new GZIPInputStream(new FileInputStream("F:/gawiki-20090614-stub-meta-history.xml.gz")); BufferedReader br = new BufferedReader(new InputStreamReader(gzip)); - Kapil D
13
@KapilD,你完全没有理解他关于编码的观点,这让我感到很难过...正如你在评论中所说的和你评论中的例子一样。请重新阅读Erickson的回答...也许要读30遍。 - James
@glyphx,您的问题不太清楚。您是想知道在没有外部内容类型断言的情况下如何识别gzip文件吗?一个提示是文件扩展名,另一个提示是文件头中存在魔数0x1F8B。但是,在您实际处理整个文件之前,您无法确定文件是否为有效的gzip文件。 - erickson
1
要明确一点,我知道这些文件是gzip文件。而且这些压缩文件都是基于文本的文件,比如csv和管道分隔符文件。我只想能够直接使用Java逐行读取这些文件。我可以gzip -d它们,然后毫不费力地逐行读取它们。我只是对你在评论中提到必须指定编码感到困惑...我认为大多数文件都是ASCII...但有些可能有亚洲字符,所以可能是UTF-8?我只是想确保我做得正确...这样清楚吗?谢谢! - glyphx
违反第二条命令意味着什么?我们是在将默认编码神化/崇拜成偶像吗? - WestCoastProjects
显示剩余3条评论

45
GZIPInputStream gzip = new GZIPInputStream(new FileInputStream("F:/gawiki-20090614-stub-meta-history.xml.gz"));
BufferedReader br = new BufferedReader(new InputStreamReader(gzip));
br.readLine();


你的回答很棒。简洁明了。然而,Erickson的回答更加详细。 - Kapil D

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

3
你可以在一个工具类中使用以下方法,需要时随时使用...
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;
}

3

这里只有一行

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接