2009-01-06 8 views
11

Dies ist vielleicht ähnlich wie in früheren Posts, aber ich möchte etwas über die Verwendung von Sperren in einem Netzwerk, anstatt lokal zu sein. Ich möchte eine Datei an einen freigegebenen Speicherort schreiben, so dass es in einem Netzwerk (sicherlich ein Windows-Netzwerk, vielleicht Mac) gehen kann. Ich möchte verhindern, dass andere Leute einen Teil dieser Datei lesen, während sie geschrieben wird. Dies wird kein sehr gleichzeitiger Prozess sein, und die Dateien werden in der Regel weniger als 10 MB sein.Java-Datei in einem Netzwerk sperren

Ich habe die FileLock Dokumentation und File Dokumentation gelesen und bin etwas verwirrt, was ist sicher und was nicht. Ich möchte die gesamte Datei statt Teile davon sperren.

Kann ich FileChannel.tryLock() verwenden, und es ist sicher in einem Netzwerk, oder hängt es von der Art des Netzwerks ab? Funktioniert es in einem Standard-Windows-Netzwerk (wenn es so etwas gibt).

Wenn dies nicht funktioniert, ist das Beste, um eine Null-Byte-Datei oder ein Verzeichnis als Sperrdatei zu erstellen, und dann die Hauptdatei ausschreiben. Warum heißt das in der Dokumentation File.createNewFile(), dass dies nicht zum Sperren von Dateien verwendet wird? Ich schätze, dass dies den Rennbedingungen unterliegt und nicht ideal ist.

Antwort

5

Dies kann nicht zuverlässig auf einem Netzwerk-Dateisystem durchgeführt werden. Solange Ihre Anwendung die einzige Anwendung ist, die auf die Datei zugreift, ist es am besten, eine Art kooperativen Sperrprozess zu implementieren (vielleicht eine Sperrdatei in das Netzwerk-Dateisystem schreiben, wenn Sie die Datei öffnen). Der Grund, der nicht empfohlen wird, ist jedoch, dass Ihre Anwendung in einen unangenehmen, schmutzigen Zustand gerät, wenn Ihr Prozess abstürzt oder das Netzwerk ausfällt oder andere Probleme auftreten.

3

Sie können eine leere Datei haben, die auf dem Server liegt, auf den Sie schreiben möchten.

Wenn Sie auf den Server schreiben möchten, können Sie das Token abfangen. Nur wenn Sie das Token haben, sollten Sie in jede Datei schreiben, die auf dem Server liegt.

Wenn Sie mit Dateioperationen fertig sind oder eine Ausnahme ausgelöst wurde, müssen Sie das Token freigeben.

können die Helfer Klasse wie

aussehen
private FileLock lock; 

private File tokenFile; 

public SLTokenLock(String serverDirectory) { 
    String tokenFilePath = serverDirectory + File.separator + TOKEN_FILE; 
    tokenFile = new File(tokenFilePath); 
} 

public void catchCommitToken() throws TokenException { 
    RandomAccessFile raf; 
    try { 
     raf = new RandomAccessFile(tokenFile, "rw"); //$NON-NLS-1$ 
     FileChannel channel = raf.getChannel(); 
     lock = channel.tryLock(); 

     if (lock == null) { 
      throw new TokenException(CANT_CATCH_TOKEN); 
     } 
    } catch (Exception e) { 
     throw new TokenException(CANT_CATCH_TOKEN, e); 
    } 
} 

public void releaseCommitToken() throws TokenException { 
    try { 
     if (lock != null && lock.isValid()) { 
      lock.release(); 
     } 
    } catch (Exception e) { 
     throw new TokenException(CANT_RELEASE_TOKEN, e); 
    } 
} 

Ihre Operationen sollte wie dann

aussehen
try { 
     token.catchCommitToken(); 

     // WRITE or READ to files inside the directory 
    } finally { 
     token.releaseCommitToken(); 
    } 
1

Anstatt eine Sperrstrategie Implementierung, die auf die Leser aller Wahrscheinlichkeit nach verlassen wird, auf Ihre haften Konvention, aber wird sie nicht zwingen, vielleicht können Sie die Datei in eine versteckte oder obskure benannte Datei schreiben, wo es für die Leser unsichtbar sein wird. Wenn die Schreiboperation abgeschlossen ist, benennen Sie die Datei in den erwarteten öffentlichen Namen um.

Der Nachteil ist, dass das Verstecken und/oder Umbenennen ohne zusätzliche E/A möglicherweise die Verwendung nativer OS-Befehle erfordert, aber das Verfahren sollte ziemlich einfach und deterministisch sein.

4

Ich habe diesen Fehlerbericht gefunden, der beschreibt, warum der Hinweis zur Dateisperrung zur File.createNewFile-Dokumentation hinzugefügt wurde.

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4676183

Darin heißt es:

Wenn Sie die Datei als deleteOnExit vor Aufruf CreateNewFile markieren, aber die Datei bereits vorhanden ist, Sie laufen Gefahr, das Löschen einer Datei Sie nicht erstellt und Fallenlassen jemandes elses sperren! Auf der anderen Seite, wenn Sie die Datei nach erstellen es zu markieren, verlieren Sie Atomizität: Wenn das Programm beendet wird, bevor die Datei markiert ist, wird es nicht gelöscht und die Sperre wird "verkeilt".

So sieht es aus wie der Hauptgrund Verriegelung mit File.createNewFile abgeraten() ist, dass Sie mit verwaisten Lock-Dateien landen können, wenn die JVM unerwartet beendet, bevor Sie eine Chance haben, es zu löschen. Wenn Sie mit verwaisten Sperrdateien umgehen können, könnte es als einfacher Sperrmechanismus verwendet werden. Allerdings würde ich die in den Kommentaren des Fehlerberichts vorgeschlagene Methode nicht empfehlen, da es Race-Bedingungen um das Lesen/Schreiben des Timestamp-Werts und das Zurückfordern der abgelaufenen Sperre hat.