2008-12-14 3 views
6

У меня есть большой файл, на котором я открываю FileInputStream. Этот файл содержит некоторые файлы, каждый из которых имеет смещение от начала и размера. Кроме того, у меня есть парсер, который должен оценивать такой файл.Хороший дизайн: как передать InputStreams в качестве аргумента?

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 в исходный поток ввода, создавая соответствующие корректировки для смещения и проверяя чтение за конец подфайла.

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

+0

Пробовал подкласс FileInputStream для создания пользовательского InputStream для моего случая. Похоже, что FIS ищет символ EOF, которого на самом деле нет. Я проверил его в SVN: http://code.google.com/p/mtmx/source/browse/code/core/trunk/mtmx.file/src/mtmx/file/internal/SubFileInputStream.java – 2008-12-14 20:57:05

+0

I не будет подкласса FileInputStream - я бы подклассифицировал только InputStream, поэтому вы можете создать частичный поток из * любого * входного потока. – 2008-12-14 21:20:00

2

Это звучит как типичный файл вложенного файла, например, «zip».

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

Вы можете forinstance иметь вид фабричного метода, который будет иметь подпись, как это:

List<InputStream> getStreams(File inputFile) 

Вы могли бы сделать то же самое с OutputStreams.

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

0

Вы можете использовать класс-обертку на RandomAccessFile - попробуйте this

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

3

Во-первых, FileInputStream.skip() has a bug, который может сделать файл под пропуском выше маркера 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 
} 

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

1

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

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

Смежные вопросы