JDK-6289846 : new FileOutputStream() truncates file despite active lock
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.nio
  • Affected Version: 1.4.2
  • Priority: P3
  • Status: Closed
  • Resolution: Won't Fix
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2005-06-23
  • Updated: 2011-02-16
  • Resolved: 2006-11-22
Description
FULL PRODUCT VERSION :
java version "1.5.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0-b64)
Java HotSpot(TM) Client VM (build 1.5.0-b64, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]

A DESCRIPTION OF THE PROBLEM :
Creating a FileOutputStream on a locked file truncates the file and therefore destroys the file content.


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the sample class as described in the javadoc comment.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The exception that is thrown in the write() method of the FileOutputStream should already be thrown when the FileOutputStream is created.
ACTUAL -
The file is truncated and the file content destroyed despite the pending lock.

ERROR MESSAGES/STACK TRACES THAT OCCUR :
The write() method throws the following exception which would be expected to be thrown when the FileOutputStream on the locked file is created.

Exception in thread "main" java.io.IOException: The process cannot access the file because another process has locked a portion of the file
	at java.io.FileOutputStream.writeBytes(Native Method)
	at java.io.FileOutputStream.write(FileOutputStream.java:247)
	at test.LockTest.main(LockTest.java:65)



REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
package test;

import java.io.File;
import java.io.FileOutputStream;
import java.nio.channels.FileLock;

/**
 * Open two console windows and go to the same directory. Run this class
 * with argument <code>lock</code> in the first console window and while
 * it sleeps start it without argument in the second window. File
 * <code>test.temp</code> will have 0 bytes length after completion in
 * the second window.
 *
 * @param av
 *     the command line arguments
 *
 * @throws Exception
 *     if something goes wrong
 */
public class LockTest
{
    public static void main(String[] av) throws Exception
    {
        final File  file = new File("test.temp");
        
        if (av[0].equals("lock"))
        {
            FileOutputStream fos  = new FileOutputStream(file);
            FileLock         lock;
            
            // lock file and write 3 bytes
            lock = fos.getChannel().lock();
            fos.write("abc".getBytes());
            
            System.out.println("LOCKER: File locked. Going to sleep.");
            
            Thread.sleep(30000);
            lock.release();
            fos.close();
        }
        else
        {
            // File length is 3 here.
            System.out.println("WRITER: file size before open = " + file.length());
            
            // Creating the FileOutputStream succeeds although the
            // file is locked. The file is truncated to length 0 and
            // therefore the file content has been destroyed despite
            // the lock!
            FileOutputStream fos = new FileOutputStream(file);
            
            // File length is 0 here.
            System.out.println("WRITER: file size after  open = " + file.length());
            
            // In the next line an IOException is thrown due to the
            // active file lock but the file content is already destroyed.
            fos.write("def".getBytes());
            
            fos.close();
        }
    }
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
if possible one can use RandomAccessFile which doesn't truncate the file
###@###.### 2005-06-23 11:36:51 GMT

Comments
EVALUATION It's not clear that we can or should do anything here. FileOutputStream(String) creates a new file. It will be platform specific if this succeeds or blocks when an existing file of that name is locked by another process. The behaviour that the submitter observes is becauses Windows will truncate the file but later fail when I/O is attemped because locking is mandatory. If the submitter wishes to make use of the file-locking API then it might be better to use a RandomAccessFile. Alternatively, use the file-locking APIs with a second file to work as an advisory for the primary/temporary file.
28-10-2005