— Привіт, Аміго!
— Привіт, Білаабо! Як життя?
— Чудово. Вчора виводив паразитів, але поки що не дуже виходить. А потім знову довелося ночувати у сміттєвому баку.
— Тобто. все як і раніше відмінно?
— Можна й так би мовити.
— Гуд. А що ми маємо сьогодні?
— Сьогодні я розповім тобі про клас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().
— Так, Аміго. Все приблизно те саме. Але ж зручно?
— Зручно. Дякую тобі, Білаабо, за цікаву лекцію і за ті приклади, які ти мені дав.
— Радий допомогти, друже Аміго!
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ