Java FileLock for Reading and Writing

非 Y 不嫁゛ 提交于 2019-11-27 01:48:43

问题


I have a process that will be called rather frequently from cron to read a file that has certain move related commands in it. My process needs to read and write to this data file - and keep it locked to prevent other processes from touching it during this time. A completely separate process can be executed by a user to (potential) write/append to this same data file. I want these two processes to play nice and only access the file one at a time.

The nio FileLock seemed to be what I needed (short of writing my own semaphore type files), but I'm having trouble locking it for reading. I can lock and write just fine, but when attempting to create lock when reading I get a NonWritableChannelException. Is it even possible to lock a file for reading? Seems like a RandomAccessFile is closer to what I need, but I don't see how to implement that.

Here is the code that fails:

FileInputStream fin = new FileInputStream(f);
FileLock fl = fin.getChannel().tryLock();
if(fl != null) 
{
  System.out.println("Locked File");
  BufferedReader in = new BufferedReader(new InputStreamReader(fin));
  System.out.println(in.readLine());
          ...

The exception is thrown on the FileLock line.

java.nio.channels.NonWritableChannelException
 at sun.nio.ch.FileChannelImpl.tryLock(Unknown Source)
 at java.nio.channels.FileChannel.tryLock(Unknown Source)
 at Mover.run(Mover.java:74)
 at java.lang.Thread.run(Unknown Source)

Looking at the JavaDocs, it says

Unchecked exception thrown when an attempt is made to write to a channel that was not originally opened for writing.

But I don't necessarily need to write to it. When I try creating a FileOutpuStream, etc. for writing purposes it is happy until I try to open a FileInputStream on the same file.


回答1:


(a) Are you aware that locking the file won't keep other processes from touching it unless they also use locks?
(b) You have to lock via a writable channel. Get the lock via a RandomAccessFile in "rw" mode and then open your FileInputStream. Make sure to close both!




回答2:


It would be better if you created the lock using tryLock(0L, Long.MAX_VALUE, true).

This creates a shared lock which is the right thing to do for reading.

tryLock() is a shorthand for tryLock(0L, Long.MAX_VALUE, false), i.e. it requests an exclusive write-lock.




回答3:


I wrote a test program and bash commands to confirm the effectivity of the file lock:

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

public class FileWriterTest
{
    public static void main(String[] args) throws Exception
    {
        if (args.length != 4)
        {
            System.out.println("Usage: FileWriterTest <filename> <string> <sleep ms> <enable lock>");
            System.exit(1);
        }

        String filename = args[0];
        String data = args[1];
        int sleep = Integer.parseInt(args[2]);
        boolean enableLock = Boolean.parseBoolean(args[3]);

        try (RandomAccessFile raFile = new RandomAccessFile(new File(filename), "rw"))
        {
            FileLock lock = null;
            if (enableLock)
            {
                lock = raFile.getChannel().lock();
            }

            Thread.sleep(sleep);
            raFile.seek(raFile.length());
            System.out.println("writing " + data + " in a new line; current pointer = " + raFile.getFilePointer());
            raFile.write((data+"\n").getBytes());

            if (lock != null)
            {
                lock.release();
            }
        }
    }
}

Run with this bash command to check it works:

for i in {1..1000}
do
java FileWriterTest test.txt $i 10 true &
done

You should see the writing only happening once every 10ms (from the outputs), and in the end all numbers to be present in the file.

Output:

/tmp wc -l test.txt
1000 test.txt
/tmp

The same test without the lock shows data being lost:

for i in {1..1000}
do
java FileWriterTest test.txt $i 10 false &
done

Output:

/tmp wc -l test.txt
764 test.txt
/tmp

It should be easy to modify it to test the tryLock instead.



来源:https://stackoverflow.com/questions/2268997/java-filelock-for-reading-and-writing

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!