views:

1272

answers:

2

Hi,

I'm trying to lock a file with Java in Windows environment with FileLock and I got an issue : after I lock the file it can still be accessed by other processes at least on some level.

Example code follows:

public class SimpleLockExample {
    public static void main(String[] args) throws Exception {
     String filename = "loremlipsum.txt";

     File file = new File(filename);
     RandomAccessFile raf = new RandomAccessFile(file, "rw");
     FileChannel channel = raf.getChannel();

     FileLock lock = null;
     try {
      lock = channel.tryLock();
      String firstLine = raf.readLine();
      System.out.println("First line of file : " + firstLine);
      waitForEnter();
      lock.release();
     } catch (OverlappingFileLockException e) {
      e.printStackTrace();
     }

     lock.release();
     System.out.println("Lock released");

     channel.close();
    }

    private static void waitForEnter() throws Exception {
     BufferedReader reader =
       new BufferedReader(new InputStreamReader(System.in));
     reader.readLine();
     reader.close();
    }
}

Now, when I lock my file with this example, it is locked :

  • It can't be deleted by Windows
  • Eclipse refuses to open it

... but it isn't still totally bulletproof:

  • If I open it with Scite (a text editor), for example, no content is shown but if I select to save the file (empty as opened or with some content written), it succeeds and the contents of the file is cleared... (no content exists there afterwards even if I had written something with Scite)

Is there some way to prevent the file totally from being overwritten/cleared by other processes with Java in Windows?

If I've understood right, I'm using exclusive lock atm. With shared lock there are even more things that can be done.

This test was run with Windows 2000.

br, Touko

+3  A: 

Tricky, the FileLock API itself doesn't promise much:

This file-locking API is intended to map directly to the native locking facility of the underlying operating system. Thus the locks held on a file should be visible to all programs that have access to the file, regardless of the language in which those programs are written.

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.

Oddly enough, the discussion about the file locking API when it was under development claimed that Windows OS provided mandatory locking and on Unix only advisory locking. So on that reading one might expect your code to work just fine on Windows.

I wonder if what is happening it that your editor is not so much modifying the file as creating a temporary file and then manipulating directory entries in order to replce the version of the file you have locked with a new version. Would Windows allow such behaviour?

I wonder if you'll need to resort to JNI in order to get the level of control you need.

djna
A: 

Your call to .tryLock() may return null if it doesn't get the lock. From the Javadoc:

A lock object representing the newly-acquired lock, or null if the lock could not be acquired because another program holds an overlapping lock

Also, your code currently opens the file and then it tries to acquire a lock. Instead you should loop trying to get the lock, and once you've got it, open the file, read the file, close the file, then give up the lock. And give up the lock in a finally {} clause, just in case your code throws an exception with the lock held. (Ever had to reboot a Windows machine just because some file was locked?)

George