Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to atomically rename a file in Java, even if the dest file already exists?

I have a cluster of machines, each running a Java app.

These Java apps need to access a unique resource.txt file concurrently.

I need to atomically rename a temp.txt file to resource.txt in Java, even if resource.txt already exist.

Deleting resource.txt and renaming temp.txt doesn't work, as it's not atomic (it creates a small timeframe where resource.txt doesn't exist).

And it should be cross-platform...

Thanks !

like image 906
Sébastien RoccaSerra Avatar asked Feb 27 '09 16:02

Sébastien RoccaSerra


People also ask

How do you rename and delete a file in Java?

You can use File. delete() and File. rename(File target) for this purpose.

How do I rename all files in a directory in Java?

A new folder is created in the path mentioned. The list of files is obtained using the 'listFiles' function. The file of array is iterated over, and if a file is encountered, a new file path is created and the name of the file is obtained and it is split. The files are renamed to .


2 Answers

For Java 1.7+, use java.nio.file.Files.move(Path source, Path target, CopyOption... options) with CopyOptions "REPLACE_EXISTING" and "ATOMIC_MOVE".

See API documentation for more information.

For example:

Files.move(src, dst, StandardCopyOption.ATOMIC_MOVE); 
like image 200
Eirik W Avatar answered Oct 06 '22 10:10

Eirik W


On Linux (and I believe Solaris and other UNIX operating systems), Java's File.renameTo() method will overwrite the destination file if it exists, but this is not the case under Windows.

To be cross platform, I think you'd have to use file locking on resource.txt and then overwrite the data.

The behavior of the file lock is platform-dependent. On some platforms, the file lock is advisory, which means that unless an application checks for a file lock, it will not be prevented from accessing the file. On other platforms, the file lock is mandatory, which means that a file lock prevents any application from accessing the file.

try {     // Get a file channel for the file     File file = new File("filename");     FileChannel channel = new RandomAccessFile(file, "rw").getChannel();      // Use the file channel to create a lock on the file.     // This method blocks until it can retrieve the lock.     FileLock lock = channel.lock();      // Try acquiring the lock without blocking. This method returns     // null or throws an exception if the file is already locked.     try {         lock = channel.tryLock();     } catch (OverlappingFileLockException e) {         // File is already locked in this thread or virtual machine     }      // Release the lock     lock.release();      // Close the file     channel.close(); } catch (Exception e) { } 

Linux, by default, uses voluntary locking, while Windows enforces it. Maybe you could detect the OS, and use renameTo() under UNIX with some locking code for Windows?

There's also a way to turn on mandatory locking under Linux for specific files, but it's kind of obscure. You have to set the mode bits just right.

Linux, following System V (see System V Interface Definition (SVID) Version 3), lets the sgid bit for files without group execute permission mark the file for mandatory locking

like image 35
Stephen Avatar answered Oct 06 '22 08:10

Stephen