2010-12-08 4 views
5

Ich habe ein Verzeichnis, das Dateien enthält, die an Clients geliefert werden, sagen wir /srv/data. Während ich eine Reihe von Aktualisierungen mache, arbeite ich an /srv/data_tmp, und am Ende der Operation möchte ich data mit data_tmp atomar ersetzen. File.renameTo() gibt immer false für mich zurück, wenn das Ziel ein vorhandenes Verzeichnis ist. Wie kann ich das machen?Wie ersetzt man in Java ein Verzeichnis atomar durch ein anderes?

+0

Haben Sie Einschränkungen für das zugrunde liegende Dateisystem? Offensichtlich, wenn es FAT ist, gibt es keine Möglichkeit, da das Dateisystem es nicht unterstützt. Weißt du, ob sich die beiden Verzeichnisse auf demselben physischen Volume befinden? Können Sie die neuen JDK7 java.nio.file APIs verwenden oder muss es auf einem JDK <= 6 arbeiten? –

+1

Ich glaube nicht, dass zwei Dateiverschiebeoperationen "atomar" im engeren Sinne des Wortes durchgeführt werden können. Einige Dateisysteme garantieren einige [atomare Operationen] (http://www.softpanorama.org/Internals/Filesystems/ntfs.shtml), aber ich kenne keine Möglichkeit, an das Betriebssystem zu verlangen, dass mehrere FS-Aktionen für alle atomar ausgeführt werden Prozesse; sicherlich nicht in Java. – maerics

+0

@Mike: Ich werde HFS +, ext3 oder NTFS, nie FAT verwenden. Es sollte mit JDK 6 funktionieren. –

Antwort

1

Ich fürchte, Sie können nicht. Zumindest nicht auf der SO-Ebene. Selbst wenn Sie "Atomizität" im Kontext Ihrer Java-Anwendung verwalten, haben Sie keine Garantie, dass ein anderer "Rogue" -Prozess auf der Ebene des tatsächlichen Dateisystems stört.

Wenn ich Sie wäre, würde ich lesen this article (ziemlich alt, aber sollte Ihnen einige Ideen geben) und dann sehen, ob Sie den vorgeschlagenen Ansatz zu einem more modern version portieren können.

Oh, warte, jemand hat schon this!

Und anscheinend Sie nicht the first one to ask here, entweder

Best of luck ...

+0

Die Apache Commons-Transaktionen erlauben mir, dies zu tun Dies ist sehr übersichtlich, wenn auch nur im Kontext meiner Java App, was mir jetzt reicht. Danke für deinen Link! –

1

Sie könnten das Verzeichnis /srv/data durch einen symbolischen Link (oder einen junction in Windows XP) ersetzen und das Ziel des Links ändern, falls dies sinnvoll ist. Sie können dies jedoch nicht mit einer Java 6-API tun - Sie müssten sich auf eine Bibliothek verlassen oder die Befehlszeilenbefehle selbst schreiben.

NB: Ich garantiere nichts über die Atomarität dieser Operation.

+0

Der Symbolik-Link-Ansatz ist interessant, aber Sie irren sich damit, dass Sie eine Datei nicht in eine Datei umbenennen können, die bereits existiert. Wenn sowohl a als auch b in "/ home/me" existieren, überschreibt dies erfolgreich b mit einem (unter Mac OS X/HFS +): 'new File ("/home/me/a "). RenameTo (neue Datei ("/home/me/b ")' –

+0

Oh, richtig, habe das nicht erwartet. –

1

Der Linux-Systemaufruf rename erlaubt dies nicht (der Systemaufruf rename kann nur ein leeres Verzeichnis überschreiben), also bezweifle ich, dass es in Java unter Linux möglich ist.

+0

Ist der Aufruf zum 'atomaren' Umbenennen? Und wenn ja, auch beim Überschreiben? –

+0

Ja, aber laut [man-Seite ] (http://linux.die.net/man/2/rename) "Beim Überschreiben wird es wahrscheinlich ein Fenster geben, in dem sowohl oldpath als auch newpath auf die Datei verweisen, die umbenannt wird." –

0

Zur Erreichung dieses Ziels ist durchaus möglich, eine Kombination aus "Symlink" verwenden und "Umbenennen", zusammen mit einem Zwischen tmp Verzeichnis. Das folgende Beispiel ist in der Schale, aber man konnte die Funktionalität hier leicht übersetzen, die zugrunde liegenden Anrufe zu verwenden:

mkdir -p tmp/real_dir1 tmp/real_dir2 
touch tmp/real_dir1/a tmp/real_dir2/a 
# start with ./target_dir pointing to tmp/real_dir1 
ln -s tmp/real_dir1 target_dir 
# create a symlink named target_dir in tmp, pointing to real_dir2 
ln -sf tmp/real_dir2 tmp/target_dir 
# atomically mv it into ./ replacing ./target_dir 
mv tmp/target_dir ./ 

Beispiel hier entnommen aus: http://axialcorps.wordpress.com/2013/07/03/atomically-replacing-files-and-directories/

Dies läuft darauf hinaus (in Pseudocode):

mkdir('./tmp'); 
mkdir('./tmp/real_dir1'); 
mkdir('./tmp/real_dir2'); 
symlink('./tmp/real_dir1', './target_dir') 
symlink('./tmp/real_dir2', './tmp/target_dir') 
rename('./tmp/target_dir', './target_dir') 

Die endgültige Umbenennung ist hier atomar, so dass die Aktion entweder erfolgreich ist oder ganz fehlschlägt, da die Aktion von dem Punkt eines Prozesses, der das Verzeichnis verwendet, atomar ist.

Verwandte Themen