Disappointment when trying to lock file for reading - java

I'm trying to make each thread read its own text file.
private void burden() {
File mainFolder = new File("C:\\FilesToRead");
File[] files = mainFolder.listFiles();
String freeFile;
for (File file : files) {
FileChannel channel;
FileLock lock = null;
try {
channel = new RandomAccessFile(file, "r").getChannel();;
lock = channel.lock();
// Ok. We get the lock
readFile(file.getName());
} catch (OverlappingFileLockException e) {
continue; // File is open by someone else
} catch (FileNotFoundException f) {
} catch (IOException ex) {
} catch (NonWritableChannelException n) {
System.out.println("NonWritableChannelException");
} finally {
try {
lock.release();
} catch (IOException ex) {
System.out.println("IOException!");
}
}
}
} // burden();
I get this picture in the debugger:
The next step will bring me to the NonWritableChannelException.
I can't understand why as I tried to lock file for reading.

The javadoc gives the answer. You use .lock(), which is equivalent to calling .lock(0L, Long.MAX_VALUE, false).
And the third parameter, a boolean, is described as (emphasis mine):
true to request a shared lock, in which case this channel must be open for reading (and possibly writing); false to request an exclusive lock, in which case this channel must be open for writing (and possibly reading)
You have to .lock(0L, Long.MAX_VALUE, true)
Also, if you are using Java 7, use FileChannel.open()

you also need to lock the writable channel here so make your code,
channel = new RandomAccessFile(file, "rw").getChannel();
This should work.

Related

FileLock in Java doesn't work in Docker mount volume

In my situation, some web configuration files are shared through mount folder in Docker. In same cases we want to modify these files concurrently. That's why I want to use lock to make sure file is being modified once at the same time. But I found flock is not working in Docker. Does it not supported?
public void modifyFile() {
try {
File file = new File("/tmp/fileToLock.dat");
// Creates a random access file stream to read from, and optionally to write to
FileChannel channel = new RandomAccessFile(file, "rw").getChannel();
// Acquire an exclusive lock on this channel's file (blocks until lock can be retrieved)
FileLock lock = null;
// Attempts to acquire an exclusive lock on this channel's file (returns null or throws
// an exception if the file is already locked.
try {
lock = channel.tryLock();
if (null != lock) {
List<String> fileToString = FileUtils.readLines(file, StandardCharsets.UTF_8);
long l = 0l;
if (null != fileToString && fileToString.size() > 0) {
l = Long.valueOf(fileToString.get(fileToString.size() - 1));
}
l++;
FileUtils.writeStringToFile(file, String.valueOf(l) + "\r\n", StandardCharsets.UTF_8, true);
}
} catch (OverlappingFileLockException e) {
// thrown when an attempt is made to acquire a lock on a a file that overlaps
// a region already locked by the same JVM or when another thread is already
// waiting to lock an overlapping region of the same file
System.out.println("Overlapping File Lock Error: " + e.getMessage());
channel.close();
}
// release the lock
if (null != lock) {
lock.release();
}
// close the channel
channel.close();
} catch (IOException e) {
System.out.println("I/O Error: " + e.getMessage());
}
}
In the end, I just leave any lock implementation for file without any Redis lock thing.

How to check file is opened or not in java is not working

I try to check file is opened or not in java using following examples . I use Apache Commons IO library...
boolean isFileUnlocked = false;
try {
org.apache.commons.io.FileUtils.touch(yourFile);
isFileUnlocked = true;
} catch (IOException e) {
isFileUnlocked = false;
}
if(isFileUnlocked){
// Do stuff you need to do with a file that is NOT locked.
} else {
// Do stuff you need to do with a file that IS locked
}
This brings me a wrong formation . When I am not opened the exact file, this show me the file has opened. If file is not opened, result is false and this cannot be possible .
Other example is here,
public boolean isFileOpened(File file){
boolean res = false;
FileChannel channel = new RandomAccessFile(file, "rw").getChannel();
// Get an exclusive lock on the whole file
FileLock lock = channel.lock();
try {
//The file is not already opened
lock = channel.tryLock();
} catch (OverlappingFileLockException e) {
// File is open by someone else
res = true;
} finally {
lock.release();
}
return res;
}
This also brings me incorrect information.
I get these examples from here Java: Check if file is already open
Now my problem is how could I check file is opened or not in java correctly ?
Thank you.

Check if file or folder is open before delete [duplicate]

This question already has answers here:
Check if a file is open before reading it?
(2 answers)
Closed 9 years ago.
How to check if a file / folder is open before i try to delete it.
Am deleting it programmatically.. before deleting, need to check whether its opened or not
I want something like this,
if(file/folder is open){
//do not delete it
}else{
//delete it
}
I tried the below set of two codes, but nothing is working
File scrptFile=new File(dirFile);
boolean isFileUnlocked = false;
try {
org.apache.commons.io.FileUtils.touch(scrptFile);
isFileUnlocked = true;
} catch (IOException e) {
isFileUnlocked = false;
}
if(isFileUnlocked){
// Do stuff you need to do with a file that is NOT locked.
System.out.println("file is not locked");
} else {
// Do stuff you need to do with a file that IS locked
System.out.println("file is locked");
}
File file = new File(dirFile);
FileChannel channel = new RandomAccessFile(file, "rw").getChannel();
// Get an exclusive lock on the whole file
FileLock lock = channel.lock();
try {
lock = channel.tryLock();
// Ok. You get the lock
System.out.println("Ok. You get the lock");
} catch (OverlappingFileLockException e) {
// File is open by someone else
System.out.println("File is open by someone else");
} finally {
lock.release();
}
You can make use of Apache commons io api,
boolean flagFileNotInUse = false;
try {
org.apache.commons.io.FileUtils.touch(yourFile);
flagFileNotInUse = true;
} catch (IOException e) {
flagFileNotInUse = false;
}
// Then check value of flagFileNotInUse ,
flagFileNotInUse = true, means file not in use
flagFileNotInUse = false, means file in use

Does IOUtils.copy block until writing is finished?

Here's my situation: I'm using IOUtils to copy a file. The next thing I do is send a JSON message to another program to say, "You can download the copy". The problem is about 25% of the time the other program gets an error saying "Received unexpected EOF downloading artifact".
Every time this error occurs, if I try again manually, the error doesn't occur. My theory is that IOUtils.copy doesn't block and the OS is still writing the file to the FS while the other program tries to download it. Is there a way to force IOUtils.copy or other functionally equivalent code to block until the OS has finished writing the file? Or is my theory incorrect? Here's the code I'm using:
private boolean archiveArtifact(String archivePath, String deployId, Artifact artifact) {
InputStream inputStream = null;
FileOutputStream fileOutputStream = null;
boolean successful = true;
try {
File archiveDir = new File(archivePath);
File deployDir = new File(archiveDir, deployId);
if (!deployDir.exists()) {
deployDir.mkdirs();
}
URLConnection connection = new URL(artifact.getJenkinsUrl()).openConnection();
inputStream = connection.getInputStream();
File output = new File(deployDir, artifact.getFileName());
fileOutputStream = new FileOutputStream(output);
IOUtils.copy(inputStream, fileOutputStream);
} catch (IOException e) {
successful = false;
logger.error(e.getMessage(), e);
} finally {
try {
if (fileOutputStream != null) {
fileOutputStream.close();
}
} catch (IOException e) {
successful = false;
logger.error(e.getMessage(), e);
}
try {
if (inputStream != null) {
inputStream.close();
}
} catch (IOException e) {
successful = false;
logger.error(e.getMessage(), e);
}
}
return successful;
}
It might be worth noting that I'm copying this to a NFS. Keep in mind I don't really know anything about NFS. This is CentOS release 5.9 (Final).
Your current code only ensures that the file content is passed to the operating system for writing; it does not guarantee that it is actually written to a the disk.
To be certain that the file is actually written to disk you can call sync() on the FileDescriptor:
fileOutputStream.flush();
fileOutputStream.getFD().sync();

Java - locking a file for exclusive access

My problem is this: I'm using a WatchService to get notified about new files in a specific folder, now if a file gets moved/copied or created in said folder an event gets triggered and the name of the new file gets returned. The problem now is, if I try to access the file and it is not fully there yet (e.g. the copy is still in progress) an exception gets raised. What i tried was to do something like this:
RandomAccessFile raf = new RandomAccessFile(fileName, "rw");
FileChannel fc = raf.getChannel();
FileLock lck = fc.lock();
But even if a lock gets acquired, sometimes still an Exception gets raised if I try to write to the file because another process has still an open handle to it.
Now, how can a file in Java be locked for truly exclusive access?
For me, the statement
RandomAccessFile raf = new RandomAccessFile(fileName, "rw");
returns a FileNotFoundException if I cannot acquire a lock on the file. I catch the filenotfound exception and treat it...
public static boolean isFileLocked(String filename) {
boolean isLocked=false;
RandomAccessFile fos=null;
try {
File file = new File(filename);
if(file.exists()) {
fos=new RandomAccessFile(file,"rw");
}
} catch (FileNotFoundException e) {
isLocked=true;
}catch (Exception e) {
// handle exception
}finally {
try {
if(fos!=null) {
fos.close();
}
}catch(Exception e) {
//handle exception
}
}
return isLocked;
}
you could run this in a loop and wait until you get a lock on the file. Wouldn't the line
FileChannel fc = raf.getChannel();
never reach if the file is locked? You will get a FileNotFoundException thrown..
its better not to use classes in thejava.io package, instead use the java.nio package .
The latter has a FileLock class that you can use for a lock to a FileChannel.
try {
// Get a file channel for the file
File file = new File("filename");
FileChannel channel = new RandomAccessFile(file, "rw").getChannel();
// Use the file channel to create a lock on the file.
// This method blocks until it can retrieve the lock.
FileLock lock = channel.lock();
/*
use channel.lock OR channel.tryLock();
*/
// Try acquiring the lock without blocking. This method returns
// null or throws an exception if the file is already locked.
try {
lock = channel.tryLock();
} catch (OverlappingFileLockException e) {
// File is already locked in this thread or virtual machine
}
// Release the lock - if it is not null!
if( lock != null ) {
lock.release();
}
// Close the file
channel.close();
} catch (Exception e) {
}

Categories

Resources