|
Neben der stream-basierten Ein- und Ausgabe bietet die Java-Klassenbibliothek auch die Möglichkeit des wahlfreien Zugriffs auf Dateien. Dabei wird eine Datei nicht als sequentielle Folge von Bytes angesehen, sondern als eine Art externes Array, das an beliebiger Stelle gelesen oder beschrieben werden kann.
Für den Zugriff auf Random-Access-Dateien stellt das Paket java.io die Klasse RandomAccessFile zur Verfügung. Anders als bei der stream-orientierten Ein-/Ausgabe kann dabei allerdings nur auf Dateien zugegriffen werden; die Verwendung von Arrays oder Pipes als Dateiersatz wird nicht unterstützt. Auch das durch die Streams realisierte Filterkonzept ist in Random-Access-Dateien nicht zu finden.
Die Klasse RandomAccessFile stellt Methoden zum Anlegen neuer Dateien und zum Öffnen vorhandener Dateien zur Verfügung. Für den lesenden oder schreibenden Zugriff auf die Datei gibt es ähnliche Methoden wie bei der sequentiellen Dateiverarbeitung. Zusätzlich kann der Satzzeiger wahlfrei positioniert werden, und es ist möglich, seine aktuelle Position abzufragen.
Das Öffnen von Random-Access-Dateien erfolgt mit dem Konstruktor der Klasse RandomAccessFile, der in zwei verschiedenen Varianten zur Verfügung steht:
public RandomAccessFile(File file, String mode) throws IOException public RandomAccessFile(String name, String mode) throws FileNotFoundException |
java.io.RandomAccessFile |
Bei der Übergabe des String-Parameters name wird die Datei mit diesem Namen geöffnet und steht für nachfolgende Schreib- und Lesezugriffe zur Verfügung. Bei der Übergabe eines File-Objekts wird die durch dieses Objekt spezifizierte Datei geöffnet. Der zweite Parameter mode gibt die Art des Zugriffs auf die Datei an. Er kann entweder "r" sein, um die Datei nur zum Lesen zu öffnen, oder "rw", um sie zum Schreiben und Lesen zu öffnen. Ein reiner Schreibmodus, wie er beispielsweise unter UNIX möglich wäre, wird nicht unterstützt.
Während der Testphase des JDK 1.2 wurde die Deklaration der Konstruktoren teilweise dahingehend geändert, daß bei Zugriffsproblemen nicht mehr die Ausnahme IOException, sondern FileNotFoundException ausgelöst wird. Gründe für eine der beiden Ausnahmen können sein, daß eine nicht vorhandene Datei zum Lesen geöffnet werden soll, daß der Dateiname ein Verzeichnis bezeichnet oder daß keine ausreichenden Zugriffsrechte auf die Datei zur Verfügung stehen. |
![]() |
|
![]() |
Leider gibt es in der Klasse RandomAccessFile keine explizite Differenzierung zwischen dem Öffnen einer Datei zum Schreiben und dem Neuanlegen. Hier gilt die implizite Regel, daß eine Datei neu angelegt wird, wenn sie beim Öffnen im Modus "w" nicht vorhanden ist. Existiert sie dagegen bereits, wird sie unverändert geöffnet, und es gibt keine Möglichkeit, ihren Inhalt zu löschen oder die Dateilänge auf einen bestimmten Wert zu setzen. Glücklicherweise bietet die Klasse File mit der Methode delete die Möglichkeit, eine Datei zu löschen und so das Neuanlegen über einen kleinen Umweg doch zu erreichen. |
![]() |
|
![]() |
Das Schließen einer Random-Access-Datei erfolgt wie bei Streams durch Aufruf der parameterlosen Methode close. Diese leert zunächst alle internen Puffer und ruft dann die korrespondierende Betriebssystemfunktion zum Schließen der Datei auf.
Einer der Hauptunterschiede zwischen dem sequentiellen und dem wahlfreien Zugriff auf eine Datei besteht darin, daß beim wahlfreien Zugriff mit einem expliziten Satzzeiger gearbeitet wird. Jeder Schreib- und Lesezugriff erfolgt dabei an der Position, die durch den aktuellen Inhalt des Satzzeigers bestimmt wird, und positioniert den Zeiger um die Anzahl gelesener bzw. geschriebener Bytes weiter. Die Klasse RandomAccessFile stellt eine Reihe von Methoden zum Zugriff auf den Satzzeiger zur Verfügung:
public long getFilePointer() public void seek(long pos) public void skipBytes(int n) public long length() |
java.io.RandomAccessFile |
getFilePointer liefert die aktuelle Position des Satzzeigers; das erste Byte einer Datei steht dabei an Position 0. Da der Rückgabewert vom Typ long ist, unterstützt Java den Zugriff auf Dateien, die größer als 2 GByte sind, sofern es das Betriebssystem zuläßt.
Das Positionieren des Satzzeigers erfolgt mit der Methode seek, die den Satzzeiger an die durch pos angegebene Stelle positioniert. Anders als in C bezieht sich der Wert von pos dabei immer auf den Anfang der Datei. Das Positionieren relativ zur aktuellen Position kann mit der Methode skipBytes erledigt werden. Die neue Position wird dabei aus der aktuellen Position plus dem Inhalt des Parameters n berechnet. Auch negative Werte für n sind dabei erlaubt und bewirken eine Rückwärtsverschiebung des Satzzeigers.
Für die lesenden Zugriffe auf eine Random-Access-Datei stehen die folgenden Methoden zur Verfügung:
public final boolean readBoolean() public final byte readByte() public final char readChar() public final double readDouble() public final float readFloat() public final int readInt() public final long readLong() public final short readShort() public final String readUTF() public final void readFully(byte b[]) public final void readFully(byte b[], int off, int len) public final String readLine() public final int readUnsignedByte() public final int readUnsignedShort() |
java.io.RandomAccessFile |
Sie lesen jeweils ein Element des angegeben Typs, das in dem durch die korrespondierende write...-Methode vorgegebenen binären Format vorliegen muß. readFully kann dazu verwendet werden, beliebig viele Datenbytes ungeachtet ihres Datentyps einzulesen. readLine liest eine ganze Zeile Text aus der Eingabedatei und gibt sie als String an den Aufrufer zurück.
Darüber hinaus steht auch eine Reihe von read-Methoden zur Verfügung, die zum Einlesen eines einzelnen Bytes oder einer Menge von Bytes verwendet werden können:
public int read() public int read(byte b[]) public int read(byte b[], int off, int len) |
java.io.RandomAccessFile |
Die schreibenden Zugriffe erfolgen mit analogen Methoden:
public final void writeBoolean(boolean v) public final void writeByte(int v) public final void writeBytes(String s) public final void writeChar(int v) public final void writeChars(String s) public final void writeDouble(double v) public final void writeFloat(float v) public final void writeInt(int v) public final void writeLong(long v) public final void writeShort(int v) public final void writeUTF(String str) |
java.io.RandomAccessFile |
Zusätzlich gibt es auch hier einige elementare write-Methoden :
public void write(int b) public void write(byte b[]) public void write(byte b[], int off, int len) |
java.io.RandomAccessFile |
Das folgende Listing zeigt die Verwendung der Klasse RandomAccessFile am Beispiel eines Programms, das die Signatur und Versionsnummer aus einem .class-File herausliest. Die Signatur einer Klassendatei ergibt das Wort »CAFEBABE«, wenn man die hexadezimale Darstellung der ersten vier Bytes ausgibt. In den nächsten beiden Bytes folgt die Minor-Versionsnummer und in den darauffolgenden zwei Bytes die Major-Versionsnummer. Das nachfolgende Programm implementiert eine Klasse ClassFileReader, die den Zugriff auf die Klassendatei ermöglicht. Der Konstruktor öffnet die Datei, und die Ausgabe der Signatur und Versionsinformation erfolgt mit Hilfe der Methoden printSignature und printVersion. Das Einlesen der Signatur erfolgt durch Lesen der ersten 4 Bytes der Datei, die dann jeweils in High- und Lowbyte zerlegt und in ihre hexadezimale Darstellung umgewandelt werden. Bei der Verwendung der Methode read zum Einlesen der Bytes ist zu beachten, daß der Rückgabewert vom Typ int ist. Er darf auch nicht in ein byte konvertiert werden, weil es sonst einen Vorzeichenüberlauf geben würde. Das Einlesen der Versionsnummern erfolgt mit der Methode readShort, die einen vorzeichenlosen 16-Bit-Wert aus der Datei liest. Auch hier ist der Rückgabewert vom Typ int, um den gesamten Wertebereich von 0 bis 65535 darstellen zu können.
|
![]() |
|
![]() |
Die Ausgabe des Programms ist:
Signatur...... CAFEBABE
Version....... 45.3
|
Go To Java 2, Addison Wesley, Version 1.0.2, © 1999 Guido Krüger, http://www.gkrueger.com |