How does FileLock work?

Solution 1:

The message about another process just means that some process on your system has the file open. It does not actually check that that process happens to be the same as the one attempting to delete/rename the file. In this case, the same program has the file opened. You have opened it to get the lock. The lock here has little to no value, especially if you are doing this for delete or rename operations.

To do what you want, you would need to lock the directory entry. This is not available in Java and may not be available in Windows. These (delete and insert) operations are atomic. That means that the operating system takes care of locking the directory and other file system structures for you. If another process (or your own) has the file open then these operations will fail. If you are trying to lock the file exclusively (directory entry) and another process (or your own) has the file open, then the lock will fail. There is no difference, but attempting to do the lock just complicates, and in this case, makes the operation impossible (that is, the files are always opened before you attempt to do the operation).

Now writing to the file is a valid lock operation. Lock the file or portion of the file that you want to write to and then it will work. On Windows, this lock mechanism is mandatory so another open/file descriptor will not be able to write to any portion that is under the lock.

EDIT

According to the JavaDoc on FileChannel.lock, it is the same as calling FileChannel.lock(0L, Long.MAXVALUE, false). This is an exclusive lock on a region from the first byte to the last.

Second, according to JavaDoc on FileLock

Whether or not a lock actually prevents another program from accessing the content of the locked region is system-dependent and therefore unspecified. The native file-locking facilities of some systems are merely advisory, meaning that programs must cooperatively observe a known locking protocol in order to guarantee data integrity. On other systems native file locks are mandatory, meaning that if one program locks a region of a file then other programs are actually prevented from accessing that region in a way that would violate the lock. On yet other systems, whether native file locks are advisory or mandatory is configurable on a per-file basis. To ensure consistent and correct behavior across platforms, it is strongly recommended that the locks provided by this API be used as if they were advisory locks.

EDIT

For the testWrite method. The JavaDoc on the commons I/O static method is sparse but says "Writes a String to a file creating the file if it does not exist.." and being as this method takes a File instead of an opened stream, it likely opens the file internally. Probably it is not opening the file with shared access and also opening for append access. This means that the existing open and lock (your open to get the channel from which to get the lock) are blocking that use. To understand even more, you would need to get the source for that method and look at what it is doing.

EDIT

Sorry, I stand corrected. I checked the Windows API and file locking is mandatory on Windows. This is why the write fails. The first open (your new RandomAccessFile) and lock has the file locked. The open to write the string succeeds but the write fails because another open (file descriptor) has the full extent of the file under mandatory exclusive lock - that is, no other file descriptor can write to the file until the lock is released.

Note that locking is associated with the file descriptor NOT process or thread.

Solution 2:

The lock you've for is locking a region inside a file, but not the file itself, so while region is locked you can't delete or rename the file.

You may want to look at the Commons Transaction project.

Solution 3:

The delete and rename operations are performed by the operating system and are atomic (on most operating systems), so no locking is required.

To write a string to file, it would be simpler to write to a temporary file first (e.g. foo.tmp) and then rename it once it is ready.