Damit eine Datei gegen konkurrierenden parallelen Zugriff geschützt ist, lässt sie sich über Locking absichern. Um einen Lock für Dateien zu erwerben bietet die Java-API ein FileLock-Objekt. So ein FileLock bekommt ein Programm von der Methode lock() eines FileChannels – ein FileChannel wiederum kommt von getChannel(), einer Methode, die FileInputStream, FileOutputStream oder RandomAccessFile anbieten.
Beispiel: Öffne eine Datei, erzeuge exklusiven Zugriff, und schreibe Daten:
FileOutputStream fos = new FileOutputStream( file );
try ( FileLock fileLock = fos.getChannel().tryLock() ) {
fos.write( … );
}
Hinweis: Die übliche Schreibweise OutputStream fos funktioniert natürlich nicht, da ein allgemeiner OutputStream keine getChannel()-Methode bietet.
Die lock(…)-Methode liefert als Ergebnis ein FileLock-Objekt. Das wiederum bietet einige Methoden, wobei für uns nur release() bzw. close() interessant sind, die den Lock wieder freigeben. FileLock implementiert die Schnittstelle AutoCloseable, sodass ein FileLock auch auch try-mit-Ressourcen verwendet werden kann, wie im Beispiel geschehen.
Um zu testen, ob eine gegebene Datei gelockt ist, lässt sich tryLock() verwenden – etwa mit der folgenden statischen Hilfsmethode:
public static boolean isLocked( String filename ) {
try ( RandomAccessFile raf = new RandomAccessFile( filename, "rw" ); FileLock lock = raf.getChannel().tryLock() ) {
// Nothing to do here
}
catch ( IOException e ) {
return false;
}
return true;
}
Die Methoden tryLock(…) und lock(…) liefern FileLock-Objekt und diese Ressource muss immer korrekt geschlossen werden.
Hinweis: Unter Unix-Systemen gibt es kein eindeutig vorgeschriebenes Verfahren zum File-Locking[1], sodass Oracle das Sperren bisher nur so umsetzt, dass zwei Java-Programme sich gegenseitig nicht in die Quere kommen, es aber sein kann, dass ein anderes Unix-Programm diesen Lock nicht respektiert. So kann unter Unix eine Datei von mehreren Seiten gelesen werden, selbst wenn ein Java-Programm sie aktuell beschreibt. Auch kann eine Datei auf dem Dateisystem gelöscht werden, selbst wenn das Java-Programm sie noch offen hält. Das Windows-Betriebssystem unterstützt hingegen Locks. Wenn ein Prozess keinen Lock auf die Datei besitzt, kann der Prozess die Datei auch nicht lesen.
[1] Zum Beispiel mit dem Alleskönner fcntl() aus dem POSIX-Standard oder flock() von 4.2 BSD.