"Cześć, Amigo!"

„Cześć, Bilaabo! Jak tam życie?”

"Świetnie. Wczoraj próbowałem pozbyć się kilku pasożytów, ale jak dotąd nie odniosłem większego sukcesu. A potem znowu musiałem spędzić noc w śmietniku."

"Więc... czy nadal wszystko jest w porządku?"

"Moglbys to powiedziec."

- Dobrze. Więc co masz dzisiaj dla mnie?

„Dzisiaj opowiem o klasie RandomAccessFile ”.

RandomAccessFile itp. - 1

„Rzecz w tym, że FileInputStream i FileOutputStream reprezentują pliki jako strumienie: można je tylko odczytywać i zapisywać sekwencyjnie”.

„Nie zawsze jest to bardzo wygodne. Czasami trzeba napisać kilka wierszy w środku pliku lub przeczytać kilka stron tekstu z końca wielomegabajtowego pliku. Czytanie nie byłoby zbyt wydajne cały plik dla tych zadań”.

„ Klasa RandomAccessFile została stworzona, aby rozwiązać ten problem. Możesz jej użyć do zapisu w dowolnym miejscu pliku, odczytu z niego, a także jednoczesnego odczytu i zapisu do pliku”.

"Jakie interesujące!"

„Tak. Właściwie to całkiem wygodne”.

„Ale jak czytać z dowolnego miejsca?”

„To wszystko jest całkiem proste. Wyobraź sobie, że masz otwarty edytor tekstu, taki jak Notatnik. Ma on kursor. Kiedy coś wpisujesz, tekst jest dodawany w miejscu, w którym znajduje się kursor. Odczyt pliku jest taki sam. gdziekolwiek jest „kursor”. Podczas czytania/zapisywania kursor porusza się automatycznie”.

„Tutaj lepiej będzie pokazać ci przykład:”

Czytanie pliku:
// r - read, the file is opened only for reading.
RandomAccessFile raf = new RandomAccessFile("input.txt", "r");

// Move the «cursor» to the 100th character.
raf.seek(100);

// Read the line starting from the current cursor position until the end of the line.
String text = raf.readLine();

// Close the file.
raf.close();

„W tym przykładzie chciałbym zwrócić uwagę na dwie rzeczy:”

"Najpierw utworzenie obiektu RandomAccessFile . Drugim argumentem jest litera r. Oznacza to, że plik jest otwarty do odczytu ( r - read ). Jeśli chcesz otworzyć plik do odczytu i zapisu, musisz przekazać « rw » do konstruktora, zamiast po prostu « r »."

„Po drugie, spójrz na metodę wyszukiwania. Możesz użyć tej metody, aby przeskakiwać po pliku i zmieniać pozycję kursora dla bieżącej operacji odczytu/zapisu. Kiedy plik jest otwierany po raz pierwszy, kursor jest ustawiany na bajcie 0. Lub, dokładniej, przed bajtem zerowym”.

„Czy dobrze zrozumiałem? Otwieramy plik, a kursor jest na samym początku — na pozycji 0. Następnie wywołujemy seek i przesuwamy kursor do setnego bajtu. A kiedy wywołujemy readLine , zaczyna czytać od setnego bajtu . Prawidłowy?"

„Tak. Ale chcę zwrócić twoją uwagę na fakt, że metoda seek pozwala na dowolne przeskakiwanie po pliku. Na przykład:”

Czytanie pliku:
// r - read, the file is opened only for reading.
RandomAccessFile raf = new RandomAccessFile("input.txt", "r");

// The "cursor" is at the 0th character.
String text1 = raf.readLine();

// Move the "cursor" to the 100th character.
raf.seek(100);
String text2 = raf.readLine();

// Move the "cursor" to the 0th character.
raf.seek(0);
String text3 = raf.readLine();

// Close the file
raf.close();

„W tym przykładzie najpierw czytamy wiersz zaczynający się od bajtu 0. Następnie przeskakujemy do bajtu setnego i czytamy tam wiersz. Następnie ponownie przeskakujemy do bajtu 0 i czytamy wiersz. Oznacza to, że tekst1 i tekst3 są identyczne smyczki."

„Ach. To czyni sprawę jaśniejszą”.

„Świetnie. Oto kolejny przykład:”

Czytanie pliku:
// rw - read/write, the file is opened for reading and writing.
RandomAccessFile raf = new RandomAccessFile("seek.txt", "rw");

// Write to the file, starting from the 0th byte.
raf.writeBytes("It is a string");

// Move the "cursor" to the 8th character.
raf.seek(8);

// Write "surprise!" to the file.
raf.writeBytes("surprise!");

// Close the file.
raf.close();

„Tutaj otwieramy plik do odczytu i zapisu, przekazując « rw » ( odczyt/zapis ) do konstruktora”.

„Następnie piszemy « It is a string » do pliku.

„Następnie przesuwamy kursor do ósmego bajtu (który jest początkiem słowa„ łańcuch ”)”

„Wtedy piszemy « niespodzianka !»”

„W rezultacie plik zawiera « To niespodzianka

„Więc bajty nie są wstawiane w środku pliku, ale raczej zastępują te, które tam były?”

"Tak."

„Co jeśli przesuniemy kursor na sam koniec pliku?”

„Wtedy bajty zostaną zapisane do końca, a plik powiększy się. Byłoby to prawie jak pisanie tekstu w edytorze tekstu”.

„Hmm. Chyba wszystko rozumiem. Czy mógłbyś podać pełną listę metod klasy RandomAccessFile ?”

"Jasne, prosze:"

metoda Opis
int read() Odczytuje jeden bajt i zwraca go
int read(byte b[], int off, int len) Odczytuje tablicę bajtów
int read(byte b[]) Odczytuje tablicę bajtów
void readFully(byte b[]) Odczytuje tablicę bajtów i czeka na dodanie nowych bajtów, jeśli nie ma ich wystarczająco dużo, aby wypełnić tablicę
int skipBytes(int n) Pomiń n bajtów. Innymi słowy, przesuwa kursor o n bajtów do przodu.
void write(int b) Zapisuje jeden bajt w lokalizacji kursora
void write(byte b[]) Zapisuje tablicę bajtów w lokalizacji kursora
void write(byte b[], int off, int len) Zapisuje tablicę bajtów w lokalizacji kursora
long getFilePointer() Zwraca numer bajtu, na który wskazuje kursor. Może wynosić od 0 do długości pliku
void seek(long pos) Przesuwa «kursor» używany do odczytu/zapisu w określone miejsce
long length() Zwraca długość pliku
void setLength(long newLength) Ustawia nową długość pliku. Jeśli plik był większy, zostanie obcięty; jeśli był mniejszy, to rozszerza plik i wypełnia nowe miejsce zerami
void close() Zamyka plik
boolean readBoolean() Odczytuje wartość logiczną z bieżącej pozycji kursora w pliku
byte readByte() Odczytuje bajt z bieżącej pozycji kursora w pliku
char readChar() Odczytuje znak z bieżącej pozycji kursora w pliku
int readInt() Odczytuje int z bieżącej pozycji kursora w pliku
long readLong() Odczytuje długą z bieżącej pozycji kursora w pliku
float readFloat() Odczytuje liczbę zmiennoprzecinkową z bieżącej pozycji kursora w pliku
double readDouble() Odczytuje podwójne z bieżącej pozycji kursora w pliku
String readLine() Odczytuje wiersz z pliku i zwraca go
void writeBoolean(boolean v) Zapisuje wartość logiczną do pliku (zaczynając od pozycji kursora)
void writeByte(int v) t Zapisuje bajt do pliku (zaczynając od pozycji kursora)
void writeChar(int v) Zapisuje znak do pliku (zaczynając od pozycji kursora)
void writeInt(int v) Zapisuje int do pliku (zaczynając od pozycji kursora)
void writeLong(long v) Zapisuje long do pliku (zaczynając od pozycji kursora)
void writeFloat(float v) Zapisuje float do pliku (zaczynając od pozycji kursora)
void writeDouble(double v) Zapisuje double do pliku (zaczynając od pozycji kursora)
void writeBytes(String s) Zapisuje String do pliku (zaczynając od pozycji kursora)
void writeChars(String s) Zapisuje String do pliku (zaczynając od pozycji kursora)

„Hmm. Więc nie ma tu nic nowego. Może z wyjątkiem par metod seek()/getFilePointer() i length()/setLength()”.

„Tak, Amigo. Wszystko jest mniej więcej takie samo. Ale czy to nie wygodne?”

„To wygodne. Dziękuję, Bilaabo, za interesującą lekcję i przykłady, które mi dałeś”.

"Cieszę się, że mogłem pomóc, Amigo, mój przyjacielu!"