InputStream, mark(), reset()

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

import java.io.*;

class BufferedInputStreamDemo {
    public static void main(String args[]) {
        String s = "© is a copyright symbol, "
                + "however &copy isn't.\n";
        byte buf[] = s.getBytes();

        ByteArrayInputStream in = new ByteArrayInputStream(buf);
        int c;
        boolean marked = false;

        //try_with_resources
        try (BufferedInputStream f = new BufferedInputStream(in)) {
            while ((c = f.read()) != -1) {
                switch (c) {
                    case '&':
                        if (!marked) {
                            f.mark(32);
                            marked = true;
                        } else {
                            marked = false;
                        }
                        break;
                    case ';':
                        if (marked) {
                            marked = false;
                            System.out.print("(c)");
                        } else
                            System.out.print((char) c);
                        break;
                    case ' ':
                        if (marked) {
                            marked = false;
                            f.reset();
                            System.out.print("&");
                        } else
                            System.out.print((char) c);
                        break;
                    default:
                        if (!marked)
                            System.out.print((char) c);
                        break;
                }
            }
        } catch (IOException e) {
            System.out.println("I/O Error: " + e);
        }
    }
}

Ответ 1

Когда f.mark(32); достигнут, курсор чтения уже после &, и маркер установлен для reset, чтобы узнать, куда отскакивать. Поэтому, когда вы обнаружили, что для закрытия элемента отсутствует ;, вы вручную печатаете & и перемещаете курсор чтения назад (после &, где был помещен маркер, с помощью вызова mark(32)), используя метод reset. При следующем чтении, поскольку ваша переменная marked не установлена, она будет печатать символы.

mark(32) означает автоматическое удаление маркера, если ваш курсор чтения будет превышать 32 символа. Это может быть проблемой в вашем другом коде, что вызывает ошибку, поскольку маркер уже недействителен.

Ответ 2

См. документацию по API:

mark(int)

Отмечает текущую позицию в этом входном потоке. Последующий вызов метода reset репозиционирует этот поток в последней помеченной позиции, чтобы последующие чтения перечитывали одни и те же байты.

Аргумент readlimit указывает этому входному потоку, чтобы позволить многим байтам считываться до того, как позиция метки становится недействительной.

Этот метод просто выполняет in.mark(readlimit).

reset()

Переводит этот поток в позицию во время последнего вызова метода меток на этот входной поток.

Этот метод просто выполняет in.reset().

Знаки потока предназначены для использования в ситуациях, когда вам нужно немного прочитать немного, чтобы увидеть, что в потоке. Часто это проще всего сделать, вызвав некоторый общий синтаксический анализатор. Если поток относится к типу, обрабатываемому синтаксическим разбором, он просто радуется счастливо. Если поток не относится к этому типу, синтаксический анализатор должен выдавать исключение, когда он терпит неудачу. Если это происходит в пределах readlimit bytes, это позволяет внешнему коду reset потоку и попробовать другой синтаксический анализатор.