— Привет, Амиго!
— Привет, Билаабо! Как жизнь?
— Отлично. Вчера выводил паразитов, но пока не очень-то получается. А потом опять пришлось ночевать в мусорном баке.
— Т.е. все по-прежнему отлично?
— Можно и так сказать.
— Гуд. А что у нас будет сегодня?
— Сегодня я тебе расскажу про класс RandomAccessFile.

Дело в том, что FileInputStream и FileOutputStream представляют файлы в виде потоков: читать из них и писать в них можно только последовательно.
Это не всегда очень-то удобно. Иногда тебе нужно записать пару строк в середину файла, или прочитать пару страниц текста в конце многомегабайтного файла. Читать для этого весь файл не очень эффективно.
Для решения этой проблемы был создан класс RandomAccessFile. С его помощью можно писать в любое место файла, читать из него, а также писать и читать файл одновременно.
— Как интересно.
— Ага. Очень удобно на самом деле.
— А как читать из произвольного места?
— Все довольно просто. Представь, что у тебя открыт текстовый редактор «блокнот». В нем есть курсор. Когда ты что-то печатаешь, текст добавляется в том месте, где он стоит. С чтением файла то же самое. Чтение происходит в том месте, где стоит «курсор». При чтении/записи он сам автоматически сдвигается.
Давай, я лучше покажу тебе пример:
//r- read, файл открыт только для чтения
RandomAccessFile raf = new RandomAccessFile("input.txt", "r");
//перемещаем «курсор» на 100-й символ.
raf.seek(100);
//читаем строку, начиная с текущего положения курсора и до конца строки
String text = raf.readLine();
//закрываем файл
raf.close();
В этом примере я хотел бы обратить твое внимание на две вещи:
Во-первых, создание объекта RandomAccessFile. Вторым параметром идет буква r. Это означает, что файл открыт для чтения (r- read). Если ты хочешь открыть файл для чтения и записи, в конструктор надо передать “rw” вместо “r”.
Во-вторых, обрати внимание на метод seek. С помощью этого метода можно прыгать по файлу и менять позицию курсора для текущей операции чтения/записи. Сразу при открытии файла «курсор» устанавливается на 0-й байт. Или точнее – перед нулевым байтом.
— Правильно ли я понял, что мы открыли файл, и курсор был в его самом начале – на позиции 0. Затем мы вызвали seek и он переместился на 100-й байт. А когда вызвали readLine, то чтение уже было начиная с сотого байта. Так?
— Да. Только хочу обратить твое внимание на то, что метод seek позволяет произвольно прыгать по файлу. Пример:
//r- read, файл открыт только для чтения
RandomAccessFile raf = new RandomAccessFile("input.txt", "r");
// «курсор» стоит на 0-м символе.
String text1 = raf.readLine();
//перемещаем «курсор» на 100-й символ.
raf.seek(100);
String text2 = raf.readLine();
//перемещаем «курсор» на 0-й символ.
raf.seek(0);
String text3 = raf.readLine();
//закрываем файл
raf.close();
В данном примере мы вначале прочитали строку, начиная с 0-го байта. Затем прыгнули на сотый байт и прочитали строку там. Затем снова прыгнули на 0-й байт и прочитали строку. Т.е. text1 и text3 – это идентичные строки.
— Ага. Ситуация начинает проясняться.
— Отлично. Тогда вот тебе еще один пример:
//rw- read/write, файл открыт и для чтения и для записи
RandomAccessFile raf = new RandomAccessFile("seek.txt", "rw");
//пишем в файл строку, начиная с 0-го байта
raf.writeBytes("It is a string");
//ставим курсор на 8-й символ
raf.seek(8);
//печатаем в файл строку surprise!
raf.writeBytes("surprise!");
//закрываем файл
raf.close();
Тут мы открываем файл для чтения и записи – в конструктор передаем «rw» (read/write).
Затем пишем в файл строку «It is a string».
Затем переставляем курсор на 8-й байт (как раз на начало слова string)
Затем пишем в файл строку «surprise!»
В результате файл будет содержать «It is a surprise!»
— Т.е. байты не вставляются в середину файла, а заменяют те, которые там были?
— Ага.
— А если мы установим курсор в самый конец файла?
— Тогда байты будут писаться в конец, а файл – удлиняться. Т.е. практически то же самое, когда ты пишешь текст в текстовом редакторе.
— Гм. Вроде все понятно. А можно полный список методов класса RandomAccessFile?
— Конечно. Держи:
Метод | Описание |
---|---|
int read() |
Читает один байт и возвращает его |
int read(byte b[], int off, int len) |
Читает массив байт |
int read(byte b[]) |
Читает массив байт |
void readFully(byte b[]) |
Читает массив байт, ждет, пока добавятся новые байты, если их не хватает для заполнения массива |
int skipBytes(int n) |
Пропускает n байт. Т.е. перемещает курсор на n байт вперед |
void write(int b) |
Пишет один байт в то место, где стоит курсор |
void write(byte b[]) |
Пишет массив байт в то место, где стоит курсор |
void write(byte b[], int off, int len) |
Пишет массив байт в то место, где стоит курсор |
long getFilePointer() |
Возвращает номер байта, на который указывает «курсор». Может быть от 0 до «длины файла» |
void seek(long pos) |
Перемещает «курсор», используемый для чтения/записи, в указанное место |
long length() |
Возвращает длину файла |
void setLength(long newLength) |
Устанавливает новую длину файла. Если файл был больше – он обрезается, если меньше – расширяется и новое место заполняется нулями |
void close() |
Закрывает файл |
boolean readBoolean() |
Читает boolean с текущей позиции курсора в файле |
byte readByte() |
Читает byte с текущей позиции курсора в файле |
char readChar() |
Читает char с текущей позиции курсора в файле |
int readInt() |
Читает int с текущей позиции курсора в файле |
long readLong() |
Читает long с текущей позиции курсора в файле |
float readFloat() |
Читает float с текущей позиции курсора в файле |
double readDouble() |
Читает double с текущей позиции курсора в файле |
String readLine() |
Читает строку из файла и возвращает ее |
void writeBoolean(boolean v) |
Пишет boolean в файл (начиная с позиции курсора) |
void writeByte(int v) |
Пишет byte в файл (начиная с позиции курсора) |
void writeChar(int v) |
Пишет char в файл (начиная с позиции курсора) |
void writeInt(int v) |
Пишет int в файл (начиная с позиции курсора) |
void writeLong(long v) |
Пишет long в файл (начиная с позиции курсора) |
void writeFloat(float v) |
Пишет float в файл (начиная с позиции курсора) |
void writeDouble(double v) |
Пишет double в файл (начиная с позиции курсора) |
void writeBytes(String s) |
Пишет строку в файл (начиная с позиции курсора) |
void writeChars(String s) |
Пишет строку в файл (начиная с позиции курсора) |
— Гм. Ничего принципиально нового. Разве что пара методов seek()/getFilePointer() и length()/setLength().
— Да, Амиго. Все примерно то же самое. Но ведь удобно?
— Удобно. Спасибо тебе, Билаабо, за интересную лекцию и за те примеры, что ты мне дал.
— Рад помочь, друг Амиго!
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ