Home > OS >  java nio FileLock.release() throws ClosedChannelException and truncates my file
java nio FileLock.release() throws ClosedChannelException and truncates my file

Time:06-12

I've got e:\myfile.txt with some random contents:

abcabcxyz...abc

Then I try to use nio FileLock like below:

import java.io.*;
import java.nio.channels.*;
public class FileLockTest{
    public static void main(String[] args){
        FileLock lock = null;
        try(FileChannel ch=new FileOutputStream(args[0]).getChannel())
        {
            lock=ch.lock();//No param exclusive lock.
            //lock(0L,ch.size(),true) for shared lock.
        }catch(FileNotFoundException e){
            e.printStackTrace();
        }catch(IOException e){
            e.printStackTrace();
        }finally{
            if(lock!=null){
                try{
                    lock.release();//throws exception!
                }catch(IOException e){
                    e.printStackTrace();
                }
            }
        }
    }
}

Upon running it and I got:

PS> java FileLockTest e:\myfile.txt
java.nio.channels.ClosedChannelException
        at sun.nio.ch.FileLockImpl.release(Unknown Source)
        at FileLockTest.main(FileLockTest.java:17)

I open myfile.txt again, all contents are missing, seems FileLock has truncated it, really strange to me.

Could you help to explain what goes wrong here?

CodePudding user response:

Your content is missing because you've accessed your file with an output stream in writing mode which erases all the previous content before performing any writing operation.

If you need to keep the existing content and add new information within your file, then you need to open it in "append" mode by passing a second boolean parameter with value true.

FileChannel ch = new FileOutputStream(args[0], true)

https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/io/FileOutputStream.html#(java.lang.String,boolean)

Also, as already said in the comments, what is giving you the ClosedChannelException is the fact that FileLock is bound to a file connection which has been already closed once you've exited the try block of your try-with statement. In fact, once you've reached your finally block the connection has been closed already and any attempt to release a lock on a closed connection will fail.

So to answer your question, it's not the lock which erases your data, but rather the way how you access your file. Besides, since both FileOutputStream and FileLock implement AutoClosable, you could include both of them in the try-with statement and rewrite your code like this:

public static void main(String[] args) {
    try (FileChannel ch = new FileOutputStream(args[0], true).getChannel();
         FileLock lock = ch.lock()) {

        //do your operations....

    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
  • Related