Java — можно ли прочитать файл построчно, остановиться, а потом сразу начать читать байты там, где я остановился?

У меня проблема с попыткой проанализировать ascii-часть файла, и как только я нажму на конечный тег, НЕМЕДЛЕННО начните чтение байтов с этого момента. Все, что я знаю в Java для чтения строки или целого слова, создает буфер, который уничтожает любую возможность получить байты сразу после моей точки остановки. Единственный способ сделать это читать побайтно, находить новые строки, реконструировать все до новой строки, смотреть, является ли это моим конечным тегом, и идти оттуда?


person Tony Stark    schedule 27.08.2009    source источник


Ответы (5)


Насколько велик этот файл? Моя первая мысль - прочитать все это в ByteBuffer или ByteArrayOutputStream, не пытаясь его обработать, а затем найти тег, сравнив значения байтов. Как только вы узнаете, где заканчивается текстовая часть и начинается двоичная часть, вы обрабатываете каждую часть соответствующим образом.

person Alan Moore    schedule 27.08.2009
comment
не очень большой файл; мне нравится простота этого. я попробую. - person Tony Stark; 27.08.2009
comment
на самом деле мне действительно нравится это теперь, когда я прочитал об этом. поэтому план состоит в том, чтобы прочитать дыру в байтовом буфере (я знаю, насколько велик файл в байтах, поэтому этот буфер будет правильного размера). затем я ищу в байтовом буфере свой конечный тег, а затем прямо там нарезаю буфер. это сработает? я предполагаю, что поиск моего конечного тега будет включать поиск первого байта, и если он будет найден, проверьте второй, третий и т. д., чтобы подтвердить. - person Tony Stark; 27.08.2009
comment
является наиболее гибким вариантом с точки зрения обработки байтов для чтения обоих разделов в отдельные массивы байтов (byte[])? Есть ли способ вместо того, чтобы передавать поток ввода файлов в программу чтения файлов, я передаю массив байтов? один из массивов байтов будет заполнен текстом в кодировке ascii, и я хотел бы, если это возможно, буферизовать его и прочитать строки (например, с помощью BufferedReader или Scanner). Возможен ли такой тонкий? - person Tony Stark; 28.08.2009
comment
ах, я мог бы просто передать свой массив байтов в ByteArrayInputStream, который я мог бы передать в свой InputStreamReader для преобразования байтов в символы, верно? И оттуда в FileReader, а затем, возможно, в BufferedReader? - person Tony Stark; 28.08.2009
comment
на самом деле, я решил, что мне не нужно ничего, кроме буферизованного потока ввода, чтобы сделать все это. я найду конечный тег, прочитаю все остальное в массив байтов, сбросю буфер и нормально прочитаю первую часть в конечном итоге сканером или буферным считывателем, чтобы легко получить ASCII. - person Tony Stark; 28.08.2009

Можно, но насколько я знаю не классами из API.

Вы можете сделать это вручную — откройте его как BufferedInputStream, который поддерживает mark/reset. Вы читаете блок за блоком (byte[]) и анализируете его как ASCII. В конце концов вы накапливаете его в буфере, пока не нажмете на маркер. Но прежде чем read вы позвоните mark. Если вы считаете, что прочитали все, что вам нужно, в ASCII, вы вызываете reset, а затем вызываете read, чтобы выгрузить остальную часть ASCII-части. И теперь у вас есть BufferedInputStream (то есть InputStream), готовый для чтения двоичной части файла.

person Marian    schedule 27.08.2009
comment
подождите, как это будет работать? я не знаю, как далеко находится конечный тег, поэтому единственная структура данных, о которой я могу думать, - это arraylist. Глядя на буфер, кажется, мне нужно знать, сколько его выделить, чего я не знаю. лучший способ справиться с этим - массив? - person Tony Stark; 27.08.2009
comment
Вы прочитали 100 байт. Содержит ли он конечный маркер (легко проверить из-за кодировки ASCII)? Нет, тогда это часть цепочки. Запомните его где-нибудь (чтобы разобрать его как строку). Вы читаете следующий блок. Опять же, он не содержит конечного маркера, вы отслеживаете его. И так далее. В какой-то момент вы читаете блок с маркером конца. Вы вырезаете первую часть (до маркера), сохраняете ее для разбора строки. Вы перематываете к началу блока, читаете/пропускаете байты до маркера, и у вас есть правильный двоичный входной поток. Вы объединяете накопленные фрагменты и используете Reader. уточняется - person Marian; 27.08.2009
comment
Вам нужно быть осторожным с конечным маркером, появляющимся в двух последовательных блоках. Вы можете сохранить byte[]s как List<byte[]> перед конкатенацией, чтобы избежать повторения System.arraycopys BTW, что 100 - это плохо. Вы должны использовать что-то вроде 4096 или 16384. - person Marian; 27.08.2009

Я думаю, что лучшей идеей было бы отказаться от понятия «линии». Чтобы найти конечный тег, создайте кольцевой буфер, достаточно большой, чтобы вместить конечный тег, читать в него побайтно и после каждого байта проверять, содержит ли он тег.

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

person Michael Borgwardt    schedule 27.08.2009
comment
Я не думаю, что он может выбрать формат файла. Я видел, какие файлы он описывает. Например, я считаю, что установочный комплект Java2SE для Linux хранится точно так же. - person Marian; 27.08.2009
comment
Я не говорю, что он должен изменить формат файла, просто он не должен пытаться читать его по одному байту за раз, а не полагаться на концепцию строк. - person Michael Borgwardt; 27.08.2009
comment
@michael: есть ли стандартный класс Java для кольцевого буфера? не удалось найти соответствующий java-сайт после поиска в Google кольцевого буфера java - person Tony Stark; 27.08.2009
comment
Нет, в стандартном API нет реализации. Но это очень простая структура данных, которую можно реализовать самостоятельно. В качестве альтернативы вы можете злоупотреблять ArrayDeque для этой цели, вызывая removeFirst() для каждого add(), как только его длина сравняется с конечным тегом. - person Michael Borgwardt; 27.08.2009

Да, вы правы насчет байта за байтом. Абстракция имеет свои недостатки.

person KJ Saxena    schedule 27.08.2009
comment
@crimson: АААААААРРРРРРРРРРРГГГГГГГГГГГГГГ - person Tony Stark; 27.08.2009
comment
Сильное различие в Java между символьными и байтовыми потоками, хотя и полезно для обеспечения того, чтобы вы всегда правильно работали с данными и различали строки и их кодировки, делает это немного сложным. - person Michael Ekstrand; 27.08.2009

Файл растет или он статичен?

Если он статический, см. http://java.sun.com/javase/6/docs/api/java/nio/MappedByteBuffer.html

person Mikael Gueck    schedule 27.08.2009
comment
он статичен, но я не понимаю, как mappedbytebuffer действительно предлагает мне гораздо больше, чем обычный bytebuffer, просто для чтения всех байтов в массивы и тому подобное. - person Tony Stark; 28.08.2009