So I try to locked the file to read it, but I got IOException, any idea why?
public static void main(String[] args){
File file = new File("C:\\dev\\harry\\data.txt");
FileReader fileReader = null;
BufferedReader bufferedReader = null;
FileChannel channel = null;
FileLock lock = null;
try{
channel = new RandomAccessFile(file, "rw").getChannel();
lock = channel.lock();
fileReader = new FileReader(file);
bufferedReader = new BufferedReader(fileReader);
String data;
while((data = bufferedReader.readLine()) != null){
System.out.println(data);
}
}catch(IOException e){
e.printStackTrace();
}finally{
try {
lock.release();
channel.close();
if(bufferedReader != null) bufferedReader.close();
if(fileReader != null) fileReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
and I got this error IOException: The process cannot access the file because another process has locked a portion of the file
Might as well add this as an answer instead of a comment.
If you use the FileLock API you need to use the corresponding NIO file apis.
Reproducing my answer from here (in case it gets deleted), and adding Jeff Foster's feedback:
Considering that an instance of the OverlappingFileLockException exception is thrown, it appears that another thread in the same process is attempting to lock on the same file. This is not a conflict between A and B, but rather a conflict within B, if one goes by the API documentation on the lock() method and when the condition under which it throws OverlappingFileLockException:
If a lock that overlaps the requested
region is already held by this Java
virtual machine, or if another thread
is already blocked in this method and
is attempting to lock an overlapping
region of the same file
The only solution to prevent this, is to have any other thread in B prevented from acquiring a lock on the same file, or the same overlapping region in the file.
The IOException being thrown has a bit more interesting message. It probably confirms the above theory, but without looking at the entire source code, I cannot confirm anything. The lock method is expected to block until the exclusive lock is acquired. If it was acquired, then there ought to be no problem in reading from the file. Except for one condition. If the file has already been opened (and locked) by the same JVM in a different thread, using a File object (or in other words, a second/different file descriptor), then the attempted read on the first file descriptor will fail even if the lock was acquired (after all, the lock does not lock out other threads).
An improved design, would be to have a single thread in each process that acquires an exclusive lock on the file (while using a single File object, or a single file descriptor) for only a certain amount of time, perform the required activity in the file, and then release the lock.
As Jeff has pointed out, using the NIO APIs would probably result in resolution of the problem. This is entirely due to the possibility of the FileReader API opening a new file descriptor, which is different from the one that the lock is obtained on.
Maybe what you want is something more like:
FileInputStream fis = new FileInputStream(file);
channel = fis.getChannel();
channel.lock();
bufferedReader = new BufferedReader(new InputStreamReader(fis));
Related
I have two JVM processes running, say Process1 and Process2. Each process is running the following:
File lockFile = new File("lock");
if (!lockFile.exists()) {
lockFile.createNewFile();
}
RandomAccessFile lockRAF = new RandomAccessFile(lockFile, "rw");
FileChannel channel = lockRAF.getChannel();
FileLock fileLock;
try {
fileLock = channel.tryLock();
} catch (OverlappingFileLockException e) {
...
} ...
// do something exclusive
fileLock.release();
lockRAF.close();
lockFile.delete();
(Not showing exception handling since it is not the main point of the question).
The problem comes from deleting the file at the end where:
Process1 acquires a FileLock, does some work then releases it
Process2 acquires a lock
Process1 deletes the file
Process1 then tries to call the same code snippet again. This works because it creates a new file from which a lock is acquired.
The result is that both processes have acquired a lock which was supposed to be exclusive.
Note: this happens on Linux (Windows does not allow deleting the file when locked).
How can I solve this in a way that allows the lock file to be deleted at the end? File.deleteOnExist does not solve the issue.
I'm developing disk cache (multithread). Cache can have many users at once. That is why I can write some rules:
1) Cache can't edit (or delete) file when client reads it.
2) When cache is editing file, clients should wait for the end of editing (and after read the file).
I need to organize this lock strategy with the help of java.
I read about synchronizatioan (synchronized block and java.util.concurrent.Locks) and as I understood it can't help here.
I tried to understand the FileLock. But when client reads file, cache lock can abort reading. And if clients will lock files before reading, there will be long sequence of client to read.
I need for advice how to organize it (maybe another ways).
UPDATE
public void write(InputStream is) throws FileNotFoundException, IOException {
File file = new File("path");
try (FileOutputStream fos = new FileOutputStream(file);
FileChannel filechannel = fos.getChannel();
FileLock lock = filechannel.lock(0, Long.MAX_VALUE, false)) {
// writing....
}
}
public void read(OutputStream osToClient) throws IOException {
File file = new File("path");
try (FileInputStream fis = new FileInputStream(file);
FileChannel filechannel = fis.getChannel();
FileLock lock = filechannel.lock(0, Long.MAX_VALUE, true)) {
IOUtils.copy(fis, osToClient);
}
}
You should probably not build this yourself unless you do it for fun or for a school assignment. However, except that there are warnings about portability (so it may not work the way you expect on all platforms) FileLock should do the job. When you are reading, first get a shared lock on the file, read the file and release the lock when done, ideally in a try-with-resources block. When you are writing, get an exclusive lock (shared=false) instead. There can be multiple readers but only one writer, and when there is a writer there can be no readers.
How can I lock the file in JVM in such way that other non JVM processes can't get access for write access?
I need to read the file and while reading I want to be sure that other processes do not modify the file.
I tried creating FileInputStream and it does lock the file for deleting but it doesn't prohibit the modification of file.
I also tried RandomAccessFile:
RandomAccessFile raf = new RandomAccessFile(file, "rw");
InputStream is = Channels.newInputStream(raf.getChannel());
but it also doesn't prevent modifications.
PS: Further in the code I need InputStream
Unfortunately, this is not something Java can do - perhaps largely because it is supported in different ways on different platforms and Java needs to maintain cross platform compatibility.
I assume, from your question for example, that you are on Windows as under Linux the above code would not even prevent file deletion.
There is some detailed information on file locking at http://en.wikipedia.org/wiki/File_locking which explains the issue.
Have you tried to use FileLock? The usage will be like this snippet:
FileInputStream in = new FileInputStream(file);
try {
java.nio.channels.FileLock lock = in.getChannel().lock();
try {
Reader reader = new InputStreamReader(in, charset);
//Other actions...
} finally {
lock.release();
}
} finally {
in.close();
}
I have two java process (JAR) one is writing to a text file on every 1 min and another is reading that file and call a web service to store data in database.
Is there any way to lock the file when it is on write mode? I have observed that when wvdial is dialing a modem its create a lock file in /var/lock/ttyUSB0..LOCK I think. I want a this kind of procedure if the file is on write mode the another process could wait till write done. After writing the process can read the file content.
Please guide me to solve my issue.
Thank you
Maybe this class can help you http://docs.oracle.com/javase/7/docs/api/java/nio/channels/FileLock.html
Edit: This post might already be covering the subject How can I lock a file using java (if possible)
Exemple:
FileInputStream in = new FileInputStream(file);
try
{
java.nio.channels.FileLock lock = in.getChannel().lock();
try
{
//write
}
finally
{
lock.release();
}
}
finally
{
in.close();
}
Now in the reading process:
FileInputStream in = new FileInputStream(file);
try
{
FileLock lock = in.getChannel().tryLock();
if (lock == null)
{
//file is locked, wait or do something else
}
else
{
try
{
//read
}
finally
{
lock.release();
}
}
}
finally
{
in.close();
}
The problem you will have here is that Java cannot open() with O_EXCL, as a result you cannot create a file atomically.
Use a directory instead: creating a directory is an atomic operation. File's .mkdir() will return false if the directory cannot be created. rmdir() it when you're done.
Of course, make sure that both of your processes have write access to the base directory!
I wrote a java application that accesses a file while other Processes in other VMs try to do the same. Therefore I use the FileLock class:
FileOutputStream fos = new FileOutputStream(filePath,append);
FileChannel f = fos.getChannel();
FileLock lock;
while ((lock = f.tryLock()) == null){
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
Logger.getLogger(Util.class.getName()).log(Level.SEVERE, null, ex);
}
}
OutputStreamWriter out = new OutputStreamWriter( new FileOutputStream(filePath,append));
out.write(textToWrite);
out.close();
lock.release();
All works fine on Mac OSX, but when I run the code on Windows 7 it throws an IOException at the line
out.close();
, when trying to flush.
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)
As far as I understand from How does FileLock work?, the actual obtaining of the lock with
f.tryLock()
forbids me to access it since another process (this one apparently) has exclusive lock.
Now that strikes me as a paradoxon - how am I to obtain an exlusive lock to enable me to write to the file without danger of other processes messing with it at the same time when the actual act of obtaining the lock hinders me to do so?
And consequently why does it work on Mac OS and not on windows? I know from the JavaDocs that there are OS specific differences and difficulties with the FileLock class, but surely not with respect to its designed-for functionality.
Since this can't be the case, I am doing something wrong and this is where I ask for your help.
Thx,
M
There is no file locking on UNIX.: http://www.coderanch.com/t/551144/java/java/File-lock-doesn-prevent-threads. In fact, on UNIX, you can delete a file from under a process and it may not even notice...
So you need to use a lock file that you can check exists.
Paradoxically your code is working on Windows but not on UNIX (i.e. Mac OS), the exception should be the expected result of trying to write to a file that is locked by another process.