Хороший дизайн: как передать InputStreams в качестве аргумента?

У меня есть большой файл, в котором я открываю 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 ответов


похоже, что вам действительно нужен своего рода" частичный " входной поток - немного похожий на ZipInputStream, где у вас есть поток в потоке.

вы можете написать это сами, проксируя все методы InputStream к исходному входному потоку, делая соответствующие корректировки для смещения и проверки чтения после конца подфайла.

Это то, о чем ты говоришь?


во-первых,FileInputStream.skip () имеет ошибку что может заставить файл под пропустить за маркер EOF файла, поэтому будьте осторожны с этим.

Я лично обнаружил, что работа с Input / OutputStreams является болью по сравнению с использованием FileReader и FileWriter, и вы показываете основную проблему, которую я имею с ними: необходимость закрыть потоки после использования. Одна из проблем заключается в том, что вы никогда не можете быть уверены, правильно ли вы закрыли все ресурсы, если вы не сделаете код немного слишком осторожен, как это:

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

Это конечно плохо в том смысле, что это приведет к созданию новых объектов, все время, что может в конечном итоге едят много ресурсов. Хорошей стороной этого, конечно, является то, что поток будет закрыт, даже если код обработки файлов выдает исключение.


это звучит как типичная вложенная проблема с файлом "zip".

общий способ справиться с этим-фактически иметь отдельный экземпляр InputStream для каждого вложенного логического потока. Они будут выполнять необходимые операции над базовым потоком phsycial, а буферизация может быть как на базовом потоке, так и на логическом потоке, в зависимости от того, что подходит лучше всего. Это означает, что логический поток инкапсулирует всю информацию о размещении в базовом поток.

можно например есть метод фабрики, который бы подпись такой:

List<InputStream> getStreams(File inputFile)

вы можете сделать то же самое с OutputStreams.

есть некоторые детали, но это может быть достаточно для вас ?


В общем, код, открывающий файл, должен закрыть файл -- функция parse () не должна закрывать входной поток, так как для нее крайне самонадеянно предположить, что остальная часть программы не захочет продолжать чтение других файлов, содержащихся в большом.

вы должны решить, должен ли интерфейс для синтаксического анализа() быть просто потоком и длиной (с функцией, способной предположить, что файл правильно расположен) или интерфейс должен включать смещение (поэтому функция сначала позиционирует, а затем считывает). Обе конструкции возможны. Я был бы склонен позволить parse () выполнять позиционирование, но это не четкое решение.


вы можете использовать класс-оболочку в RandomAccessFile-try этой

вы также можете попробовать обернуть это в BufferedInputStream и посмотреть, улучшится ли производительность.