0

I am trying to exclusively lock a file in Windows 10 with openjdk 11 but it does not work as intended. It should guarantee that as long as the lock is in place, no process but my own should be able to edit/delete/... the file.

I searched for answers, but they are a) quite old and b) use the same code i do and say 'this it how it's done'.

Below is a simple example which creates a testfile and waits for 10 seconds after aquiring a lock on it before reading. The open option 'WRITE' is needed for a non-sharing lock (otherwise tryLock throws an UnsupportedOperationException).

The behaviour so far:

  • when I delete the file (in Windows Explorer) during the wait, the read still delivers the original content of the file but the file is gone from the explorer overview the moment i delete it
  • when i edit the file during the wait (e.g. with notepad++), the editor opens the file without any shown content, i can edit and save but afterwards the read returns with -1 and the file is empty

The expected behaviour:

  • any other access to the file should return a windows error (file in use) like when you have a word document open and try to delete it

What am i doing wrong?

import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;

public class TestLocking {

    public static void main(String[] args) throws Exception {

        String filename = "testfile.txt";

        Path file = Path.of(filename);
        if (!Files.exists(file)) {
            String content = "foo";
            System.out.format("File '%s' not found - create and fill with '%s'.%n%n", file.toAbsolutePath().toString(),
                    content);
            Files.write(file, content.getBytes(Charset.defaultCharset()));
        }

        FileChannel filechannel = FileChannel.open(file, StandardOpenOption.READ, StandardOpenOption.WRITE);
        FileLock lock = filechannel.tryLock(0, Long.MAX_VALUE, false);

        if (lock == null) {
            System.out.println("File already locked.");
        } else {
            System.out.println("File lock aquired.");
            Thread.sleep(10000);
            System.out.println("reading file..");
            ByteBuffer buffer = ByteBuffer.allocate(1000);
            int readBytes = filechannel.read(buffer);
            System.out.format("read %d bytes.%n", readBytes);
            buffer.flip();
            final byte[] array = new byte[buffer.remaining()];
            buffer.duplicate().get(array);
            String s = new String(array, Charset.defaultCharset());
            System.out.println("---FILE-CONTENT---");
            System.out.println(s);
            System.out.println("---FILE---END-----");
            // unlock
            lock.close();
            System.out.println("File lock released.");
        }
        filechannel.close();
    }
}

edit1: forgot the channel.close()

mamayr
  • 31
  • 4

1 Answers1

0

In Java, a file lock can be obtained using FileChannel, which provides two methods — lock() and tryLock() — for this purpose.

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.channels.OverlappingFileLockException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class FileLockTest {
    private static final Log LOG = LogFactory.getLog(FileLockTest.class);
    private static FileChannel fc;
    private static RandomAccessFile randomAccessFile;
    public FileLockTest(String fileName) throws FileNotFoundException {
        randomAccessFile = new RandomAccessFile(fileName, "rw");
    }
    public void writeToFileWithLock(String data) {
        fc = randomAccessFile.getChannel();
        ByteBuffer buffer = null;
        try (fc; randomAccessFile; FileLock fileLock = fc.tryLock()) {
            if (null != fileLock) {
                buffer = ByteBuffer.wrap(data.getBytes());
                buffer.put(data.toString().getBytes());
                buffer.flip();
                while (buffer.hasRemaining())
                    fc.write(buffer);
            }
        } catch (OverlappingFileLockException | IOException ex) {
            LOG.error("Exception occured while trying to get a lock on File... " + ex.getMessage());
        }
    }
}
Rafael Lima
  • 3,079
  • 3
  • 41
  • 105
  • i did use exactly this approach - when you look at my code example, i use tryLock() as I don't want blocking but i don't write, i want to lock the file for the duration i acquire the lock - which it it does not do – mamayr May 22 '20 at 07:28
  • oh, and i already tried it with a RandomAccessFile - same result – mamayr May 22 '20 at 07:46