8

我有一个大文件,我正在打开一个 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() 方法会大大减慢阅读过程。

4

5 回答 5

6

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

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

你说的是那种东西吗?

于 2008-12-14T19:49:38.743 回答
3

首先,FileInputStream.skip() 有一个错误,它可能会使下面的文件跳过文件的 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
}

从某种意义上说,这当然是不好的,因为这会导致一直创建新对象,最终可能会消耗大量资源。这样做的好处当然是即使文件处理代码抛出异常,流也会关闭。

于 2008-12-14T19:59:17.350 回答
2

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

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

例如,您可以拥有一种具有如下签名的工厂方法:

List<InputStream> getStreams(File inputFile)

你可以对 OutputStreams 做同样的事情。

这有一些细节,但这对你来说可能就足够了吗?

于 2008-12-14T19:48:44.390 回答
1

通常,打开文件的代码应该关闭文件—— parse() 函数不应该关闭输入流,因为它认为程序的其余部分不想继续是极其傲慢的读取包含在大文件中的其他文件。

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

于 2008-12-14T21:38:00.473 回答
0

您可以在 RandomAccessFile 上使用包装类 - 试试这个

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

于 2008-12-14T19:48:55.297 回答