Какой смысл использовать ограничение чтения метки в bufferedinputstream
Я новичок в потоках Java, я хотел бы прочитать содержимое конкретного файла, а затем нужно прочитать его с самого начала. Я создал BufferedInputStream, и я запутался в документации BufferedInputStream.mark(int markLimit)
Документация гласит:
public void mark(int readlimit)
Этот метод отмечает позицию на входе, в которую поток может быть "сброшен" путем вызова метода reset(). Параметр readlimit - это количество байтов, которые можно прочитать из потока после установки метки до того, как метка станет недействительной. Например, если mark() вызывается с пределом чтения 10, то когда 11 байтов данных считываются из потока перед вызовом метода reset(), тогда метка недействительна, и экземпляр объекта потока не требуется для помните знак.
Обратите внимание, что количество байтов, которые можно запомнить этим методом, может быть больше, чем размер внутреннего буфера чтения. Это также не зависит от подчиненного потока, поддерживающего функциональность метки / сброса.
Переопределения: отметка в классе FilterInputStream
Параметры: readlimit - количество байтов, которые можно прочитать, прежде чем метка станет недействительной **
Мой код:
public class Test {
public static void main(String[] args) throws IOException {
File resource = new File("beforeFix.txt");
FileInputStream fileInputStream = new FileInputStream(resource);
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
int i = bufferedInputStream.read();
bufferedInputStream.mark(1);
i = bufferedInputStream.read();
i = bufferedInputStream.read();
i = bufferedInputStream.read();
i = bufferedInputStream.read();
i = bufferedInputStream.read();
i = bufferedInputStream.read();
i = bufferedInputStream.read();
i = bufferedInputStream.read();
i = bufferedInputStream.read();
i = bufferedInputStream.read();
i = bufferedInputStream.read();
i = bufferedInputStream.read();
i = bufferedInputStream.read();
i = bufferedInputStream.read();
i = bufferedInputStream.read();
i = bufferedInputStream.read();
i = bufferedInputStream.read();
i = bufferedInputStream.read();
i = bufferedInputStream.read();
i = bufferedInputStream.read();
bufferedInputStream.reset();
i = bufferedInputStream.read();
i = bufferedInputStream.read();
i = bufferedInputStream.read();
i = bufferedInputStream.read();
bufferedInputStream.reset();
}
}
В приведенном выше коде я установил marklimit как 1, но знак не становится недействительным согласно документации.
Может кто-нибудь ясно объяснить мне, какова реальная цель показать это на небольшом примере?
заранее спасибо
5 ответов
Чтобы восстановить работу и вернуться к отмеченной вами позиции, данные, которые были прочитаны после того, как вы отметили их, должны быть помещены в буфер. Значение, которое вы указываете при маркировке, - это объем памяти, который должен быть зарезервирован для этого.
Поэтому, если вы намереваетесь прочитать 100 байтов перед вызовом сброса, то ваш буфер должен быть не менее 100 байтов, и это то, с чем вы должны вызывать метку.
bufferedInputStream.mark(200);
... read no more than 200 bytes ...
bufferedInputStream.reset(); // reset back to marked position
Обновить
Похоже, документация для mark
не соответствует фактическому поведению. В документации говорится:
the maximum limit of bytes that can be read before the mark position becomes invalid
Тем не менее, похоже, что это должно быть the minimum limit
или, по крайней мере, от базовых реализаций не требуется сбрасывать метку, как только будет превышен предел чтения, если они все еще могут поддерживать сброс в отмеченную позицию.
По телефону mark
с указанным пределом вы запрашиваете возможность поддержки сброса после считывания до указанного предела, вы не отказываете в возможности сверх этого. В спецификации четко сказано:
Однако поток не обязан запоминать какие-либо данные вообще, если их больше, чем
readlimit
байты читаются из потока передreset
называется.
"Не требуется" не означает "не разрешено". В спецификации просто говорится о том, чего вы не можете ожидать, чтобы работать всегда, в ней не говорится о том, чего вы всегда можете ожидать.
В случае BufferedInputStream
Легко объяснить, что происходит под капотом. каждый BufferedInputStream
имеет емкость, по умолчанию 8192, и он всегда может сбросить больше байтов, чем его текущая емкость буфера. Указав более высокий предел, вы заставите его выделять больший буфер при необходимости, чтобы выполнить гарантию.
Поскольку вы не можете запросить у потока информацию о его текущей емкости буфера, вы можете полагаться только на гарантию того, что сброс работает, пока вы не прочитаете больше байтов, чем указанное ограничение.
Легко изменить ваш пример, чтобы сделать его воспроизводимым с ошибками:
File resource = new File("beforeFix.txt");
FileInputStream fileInputStream = new FileInputStream(resource);
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream, 1);
int i = bufferedInputStream.read();
bufferedInputStream.mark(1);
i = bufferedInputStream.read();
i = bufferedInputStream.read();
bufferedInputStream.reset(); // will fail
Как говорится в документации Oracle о методе reset() InputStream (который переопределяется FilterInputStream и далее BufferedInputStream).
Общий договор сброса:
Общий договор сброса:
-Если метод markSupported возвращает true, то:
-If the method mark has not been called since the stream was created, or the number of bytes read from the stream since mark was last called is larger than the argument to mark at that last call, then an IOException **might be** thrown. (note that IOException might be thrown) -If such an IOException is not thrown, then the stream is reset to a state such that all the bytes read since the most recent call to mark (or since the start of the file, if mark has not been called) will be resupplied to subsequent callers of the read method, followed by any bytes that otherwise would have been the next input data as of the time of the call to reset.
Надеюсь, ваш вопрос решен и поможет будущим программистам.
Пожалуйста, прочтите приведенную ниже документацию, чтобы лучше понять это. У меня были такие же сомнения, как и у вас, и я решил прочитать об этом подробнее.
- Если метка метода не вызывалась с момента создания потока или количество байтов, прочитанных из потока с момента последнего вызова метки, больше, чем аргумент, который нужно отметить при этом последнем вызове, может возникнуть исключение IOException.
- Если такое исключение IOException не генерируется, то поток сбрасывается в состояние, при котором все байты, прочитанные с момента последнего вызова функции mark (или с начала файла, если метка не была вызвана), будут повторно добавлены в последующие вызывающие методы метода чтения, за которыми следуют любые байты, которые в противном случае были бы следующими входными данными на момент вызова сброса.
С первого момента теперь очень ясно, что исключение IOException не гарантируется. Итак, если вы читаете больше разрешенного количества байтов (указанный аргумент метода mark) после вызова метода mark, то это рискованная операция и не рекомендуется.
Из второго пункта вы можете понять, что произойдет, если IOException не сгенерирован.
Ссылка на документацию: https://docs.oracle.com/javase/8/docs/api/java/io/InputStream.html
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
public class Main {
static final String fileAbsolutePath = "file.txt";
public static void main(String[] args) {
// file contains 3 chars 'a', 'b', and 'c'
try (FileInputStream fileInputStream = new FileInputStream(fileAbsolutePath);
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream)) {
System.out.println((char) bufferedInputStream.read()); // prints a
bufferedInputStream.mark(2); // place mark at second byte
System.out.println((char) bufferedInputStream.read()); // prints b
System.out.println((char) bufferedInputStream.read()); // prints c
System.out.println(bufferedInputStream.read()); // prints -1
bufferedInputStream.reset(); // meaning start again from where I placed the mark
System.out.println((char) bufferedInputStream.read()); // prints b
System.out.println((char) bufferedInputStream.read()); // prints c
System.out.println( bufferedInputStream.read()); // prints -1
} catch (IOException ie) { ie.printStackTrace();}
}
}