好的设计:如何将InputStreams作为参数传递?

时间:2008-12-14 19:41:24

标签: java inputstream

我有一个大文件,我正在打开一个FileInputStream。此文件包含一些文件,每个文件都有一个从开头和大小的偏移量。此外,我有一个解析器,应该评估这样一个包含的文件。

File file = ...; // the big file
long offset = 1734; // a contained file's offset
long size = 256; // a contained file's size
FileInputStream fis = new FileInputStream(file );
fis.skip(offset);
parse(fis, size);

public void parse(InputStream is, long size) {
   // parse stream data and insure we don't read more than size bytes
   is.close();
}

我觉得这不是好习惯。有没有更好的方法来做到这一点,也许使用缓冲?

此外,我觉得skip()方法会大大减慢阅读过程。

5 个答案:

答案 0 :(得分:5)

听起来你真正想要的是一种“部分”输入流 - 有点像ZipInputStream,你在流中有一个流。

您可以自己编写,将所有InputStream方法代理到原始输入流,对偏移量进行适当调整,并检查读取子文件末尾的内容。

这是你在说什么吗?

答案 1 :(得分:3)

首先,FileInputStream.skip() has a bug可能会使下面的文件超出文件的EOF标记,因此要小心那个。

与使用FileReader和FileWriter相比,我个人发现使用Input / OutputStreams是一件痛苦的事情,并且您正在展示我遇到的主要问题:使用后需要关闭流。其中一个问题是你永远无法确定你是否已经正确地关闭了所有资源,除非你使代码有点过于谨慎:

public void parse(File in, long size) {
    try {
        FileInputStream fis = new FileInputStream(in);
        // do file content handling here
    } finally {
        fis.close();
    }
    // do parsing here
}

这当然是不好的,因为这会导致一直创建新对象,最终可能会占用大量资源。好的一面当然是即使文件处理代码抛出异常,流也会关闭。

答案 2 :(得分:2)

这听起来像是一个典型的嵌套文件,也就是“zip”文件问题。

处理此问题的常用方法是为每个嵌套逻辑流实际拥有一个单独的InputStream实例。这些将对底层的逻辑流执行必要的操作,并且缓冲可以在底层流和逻辑流上,具体取决于哪种最适合。这意味着逻辑流封装了有关基础流中放置的所有信息。

你可以forinstance有一种工厂方法,它有这样的签名:

List<InputStream> getStreams(File inputFile)

您可以对OutputStreams执行相同的操作。

有一些细节,但这对你来说已经足够了吗?

答案 3 :(得分:1)

通常,打开文件的代码应该关闭文件 - parse()函数不应该关闭输入流,因为它假定程序的其余部分不会是最大的傲慢想要继续阅读大文件中包含的其他文件。

你应该决定parse()的接口应该只是流和长度(函数能够假设文件正确定位)或者接口是否应该包含偏移量(所以函数首先定位然后读取)。两种设计都是可行的。我倾向于让解析()做定位,但这不是一个明确的决定。

答案 4 :(得分:0)

您可以在RandomAccessFile上使用包装类 - 尝试this

您也可以尝试将其包装在BufferedInputStream中,看看性能是否有所改善。