Хороший дизайн: как передать InputStreams в качестве аргумента? - PullRequest
6 голосов
/ 14 декабря 2008

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

5 голосов
/ 14 декабря 2008

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

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

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

3 голосов
/ 14 декабря 2008

Во-первых, 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
}

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

2 голосов
/ 14 декабря 2008

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

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

Например, у вас может быть такой фабричный метод, который будет иметь такую ​​подпись:

List<InputStream> getStreams(File inputFile)

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

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

1 голос
/ 15 декабря 2008

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

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

0 голосов
/ 14 декабря 2008

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

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

...