Ввод Java-файла с возможностью перемотки () / сброса ()

Мне нужно написать функцию, которая принимает что-то вроде входного потока (например, InputStream или FileChannel), чтобы читать большой файл за два прохода: один - для предварительного вычисления некоторых мощностей, а второй - для «реального». Работа. Я не хочу, чтобы весь файл загружался в память одновременно (если только он не маленький).

Is there an appropriate Java class that provides this capability? Сам FileInputStream не поддерживает mark () / reset (). Я думаю, что BufferedInputStream делает, но мне не ясно, нужно ли для этого хранить весь файл.

C настолько прост, что вы просто используете fseek (), ftell () и rewind (). :-(

 erickson02 мая 2016 г., 04:31
Джейсон, пожалуйста, не принимай мой ответ и возьмиthis one. Это хорошо, потому что обеспечивает эффективную реализацию стандартного маркируемогоInputStream API; любой потребительInputStream можно использовать без загрузки всего файла.

Ответы на вопрос(9)

java.nio.channels.FileChannel есть методposition(long) сбросить позицию обратно в ноль, как fseek () в C.

PushbackInputStream также будет работать, если вы знаете, сколько символов вы хотите перематывать

 15 июн. 2017 г., 09:59
Не правда.PushbackInputStream#unread(int b) не перематыватьb байты, но я нажимаюb на вершине потока.

Что вы хотитеRandomAccessFileInputStream - реализуетInputStream интерфейс с меткой / сбросом, иногда поиск на основеRandomAccessFiles, Существуют некоторые реализации, которые могут делать то, что вам нужно.

Один пример с источниками приведен вhttp://www.fuin.org/utils4j/index.html но вы найдете много других, ищущих в интернете, и его достаточно легко кодировать, если ни один из них не подходит точно.

Решение Вопроса

Я думаю, что ответы, ссылающиеся на FileChannel, находятся на отметке.

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

Не проверено, пользуйтесь на свой страх и риск :)

public class MarkableFileInputStream extends FilterInputStream {
    private FileChannel myFileChannel;
    private long mark = -1;

    public MarkableFileInputStream(FileInputStream fis) {
        super(fis);
        myFileChannel = fis.getChannel();
    }

    @Override
    public boolean markSupported() {
        return true;
    }

    @Override
    public synchronized void mark(int readlimit) {
        try {
            mark = myFileChannel.position();
        } catch (IOException ex) {
            mark = -1;
        }
    }

    @Override
    public synchronized void reset() throws IOException {
        if (mark == -1) {
            throw new IOException("not marked");
        }
        myFileChannel.position(mark);
    }
}
 01 нояб. 2014 г., 01:34
Это отлично сработало для меня. Я добавилmark(0); конструктору, потому что я получаю & quot; не помеченный & quot; ошибка при первом вызовеreset() и, по крайней мере в моем случае, имеет смысл для позиции сброса по умолчанию быть 0.
 03 июн. 2014 г., 20:43
Это, безусловно, лучшее решение. BufferedInput приводит к двойной буферизации больших частей или, возможно, ВСЕХ файлов. Это огромная трата. И RandomAccessFile не наследуется от InputStream, поэтому не может быть заменой тому, где вы уже используете потоки. Этот маленький класс, однако, должен быть чрезвычайно быстрым и эффективным для памяти.
 12 февр. 2015 г., 20:30
Это решение прекрасно работает, с одним небольшим изменением. Я бы удалил & quot; mark = -1 & quot; внутри метода сброса. Javadocs для сброса не указывают, что он должен сбросить метку, только положение. Это позволяет метке вызываться один раз, а затем сбрасываться, чтобы вызываться несколько раз, например, при выполнении нескольких повторных попыток.

BufferedInputStream имеетmark(readlimit) а такжеreset(). readlimit должно быть больше чемfilesize сделать отметку действительной. file.length()+1 все в порядке. Это означает, что знак действителен доreadlimit байты читаются, поэтому вы можете вернутьсяreset().

BufferedInputStream опорыmark путем буферизации содержимого в памяти. Лучше всего зарезервировать для относительно небольших прогнозируемых размеров.

Вместо,RandomAccessFile может быть использован непосредственно, или он может служить основой для конкретногоInputStream, расширенный сrewind() метод.

В качестве альтернативы, новыйFileInputStream может быть открыт для каждого прохода.

 Jason S13 июл. 2009 г., 20:14
Я переключаюсь на этот ответ, потому что мне нужно использовать интерфейс, которым я могу поделиться между обычными файлами и буферами в памяти. Grrrrr. Я пишу свой собственный интерфейс RewindableStream + классы реализации, один из которых оборачивает RandomAccessFile.

Проверьте java.io.RandomAccessFile

 Jason S07 июл. 2009 г., 22:43
Жаль, что RandomAccessFile не реализует InputStream с его методами mark () / reset (). & GT; :(
 07 июл. 2009 г., 22:53
Вы можете сделать свой собственный довольно легко (если не так элегантно), смотритеcoderanch.com/t/277378/Streams/java/… для примера
 Jason S07 июл. 2009 г., 22:39
хорошо спасибо. Похоже, я могу использовать его, чтобы открыть файл, а затем использовать FileChannel в качестве класса для управления / чтения / записи.
 Jason S07 июл. 2009 г., 23:17
спасибо, но это другое направление (доступ к RandomAccessFile как InputStream). FileChannel - нормальный класс для передачи в моем интерфейсе.

RandomAccessFile это то, что вы хотите:

fseek() is translated to RandomAccessFile#seek ftell() is translated to RandomAccessFile#getFilePointer rewind() is seek(0)

Если вы получите связанныйFileChannel отFileInputStreamВы можете использовать метод position, чтобы установить указатель на файл в любом месте файла.

FileInputStream fis = new FileInputStream("/etc/hosts");
FileChannel     fc = fis.getChannel();


fc.position(100);// set the file pointer to byte position 100;

Ваш ответ на вопрос