GZIPInputStream逐行读取


85

我有一个.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());

有人可以建议如何进行..


看看这个链接stackoverflow.com/q/6717165/779408。压缩和解压缩方法在那里表示。
Bobs

1
出于对这个世界上所有美好事物的热爱,以及出于对那些甚至编写遥远有价值的代码的开发人员的理智…….. @@谨防@erickson指出!他是指出这一点的唯一答案,这让我想哭。
詹姆斯

Answers:


142

装饰器的基本设置如下:

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 =新的BufferedReader(新的InputStreamReader(gzip));
卡皮尔D

12
@KapilD,让我很难过的是,您完全错过了他关于编码的观点……如您的评论和评论中的示例所示。重新阅读埃里克森的答案。...可能超过30次。
詹姆斯

gzip命令如何知道编码?我想从世界各地的许多linux / unix服务器中读取很多文件...所以我想确保我做对了...帖子提到的编码通常不能由文件本身确定...但是gzip -d命令似乎可以在没有单独输入的情况下在任何文件上运行...(它现在使用的是我想避开的东西),所以我想知道是否我可以弄清楚gzip是做什么来了解编码的,我可以做同样的事情。任何想法/建议都可以为我指明正确的方向吗?
glyphx

@glyphx您的问题不清楚。您的意思是在缺少关于内容类型的某些外部断言的情况下如何识别gzip文件?一个提示是文件扩展名,另一个提示是文件头中存在魔术数字0x1F8B。但是,在实际处理完整个文件之前,您不知道文件是有效的gzip文件。
erickson

1
为了清楚起见,我知道这些文件是gzip文件。压缩后的文件都是基于文本的文件,例如csv和pipe delim文件。我只希望能够直接用java逐行读取这些文件。我可以gzip -d他们,然后逐行阅读它们没问题。我只是在您关于必须指定编码的注释中感到困惑...我会认为大多数文件都是ASCII ...但是有些文件可能带有亚洲字符,所以也许是UTF-8?我只想确保我正确执行此操作?谢谢!
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();


您的回答很好。简短明了..但是,埃里克森的答案更为详细。
卡皮尔D


2

您可以在util类中使用以下方法,并在必要时使用它...

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

这是一行

try (BufferedReader br = new BufferedReader(
        new InputStreamReader(
           new GZIPInputStream(
              new FileInputStream(
                 "F:/gawiki-20090614-stub-meta-history.xml.gz"))))) 
     {br.readLine();}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.