Хороший дизайн: как передать 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 () сильно замедляет процесс чтения.

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
8
0
11 154
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

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

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

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

List<InputStream> getStreams(File inputFile)

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

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

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

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

Ответ принят как подходящий

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

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

Ты об этом говоришь?

Пытался создать подкласс FileInputStream, чтобы создать собственный InputStream для моего случая. Похоже, что FIS ищет символ EOF, которого на самом деле нет. Я проверил это в SVN: code.google.com/p/mtmx/source/browse/code/core/trunk/mtmx.fi‌ le /…

Stefan Teitge 14.12.2008 23:57

Я бы не стал подклассом FileInputStream - я бы создал подкласс только InputStream, чтобы вы могли создать частичный поток из входного потока Любые.

Jon Skeet 15.12.2008 00:20

Изменил его, проксировал FileInputStream, и теперь он работает. Он проверил его, если вы хотите взглянуть. Спасибо вам всем.

Stefan Teitge 15.12.2008 00:21

Зачем вообще ограничивать его до FileInputStream? Сам прокси InputStream. Также ваше чтение (byte [] b) в настоящий момент неверно - доступно - = b.length; должен быть доступен - = читать;

Jon Skeet 15.12.2008 00:32

Подкласс java.io.FilterInputStream, а не InputStream.

erickson 15.12.2008 03:32

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

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

Я не понимаю вашего комментария о FileInputStream vs FileReader. В обоих случаях вам нужно закрыть ресурс после завершения работы с ним. Единственное отличие состоит в том, что поток имеет дело с двоичными данными, а средство чтения - с текстом.

Jon Skeet 14.12.2008 23:28

FileReader / FileWriter - это просто удобные слои над FileInputStream / FileOutputStream, где преобразование октетов (байтов) в символы выполняется за вас. Я даже не думаю, что вам нужно выбирать тип конверсии!

Adrian Pronk 15.12.2008 00:50

Джон: Это небольшое удобство, но все же намного лучше, чем возиться напрямую с потоками. Как я уже сказал, есть несколько проблем, которые мне не нравятся в потоке ввода-вывода Java, например, системно-зависимое изменение строки, которому, к счастью, можно противодействовать с помощью BufferedWriter.nextLine () и BufferedReader.readLine ().

Esko 15.12.2008 09:56

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

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

Другие вопросы по теме