tryLock functionlaity not working for .txt files - java

If I manually open .txt file and then executed code to check if file is open or not. It always says file is not opened. But same code works as expected for any MS Office(.doc, .xls, .ppt).
Here is the code snippet:
File file = new File("F:\\abc.txt");
FileChannel channel = null;
FileLock lock = null;
try {
channel = new RandomAccessFile(file, "rw").getChannel();
// Get an exclusive lock on the whole file
try {
lock = channel.tryLock();
if (lock != null) {
System.out.println("Lock acquired on file: " + file.getAbsolutePath());
lock.release();
System.out.println("Lock released from closed file.");
System.out.println("Closing the channel of closed file.");
}
channel.close();
}
catch (OverlappingFileLockException | IOException e) {
// File is open by someone else
}
}
catch (FileNotFoundException e1) {
// File is open by someone else
}
Each time, .txt file acquires lock even though same file is opened (which is not same behavior for MS Office files ).
Is there any other way to test whether file is opened/used by other process ?

The problem is, that most programs in windows do not lock the text file. For example if you open a text file with notepad, you can delete it. That means, notepad does not acquire a lock and so you can acquire the lock in your java program.
For your test you have to use a program which actually locks a text file or rewrite your program it locks a file until you close the program. Then you can launch your program twice.

Related

How to lock document files? [duplicate]

I have a Java process that opens a file using a FileReader. How can I prevent another (Java) process from opening this file, or at least notify that second process that the file is already opened? Does this automatically make the second process get an exception if the file is open (which solves my problem) or do I have to explicitly open it in the first process with some sort of flag or argument?
To clarify:
I have a Java app that lists a folder and opens each file in the listing for processing it. It processes each file after the other. The processing of each file consists of reading it and doing some calculations based on the contents and it takes about 2 minutes. I also have another Java app that does the same thing but instead writes on the file. What I want is to be able to run these apps at the same time so the scenario goes like this. ReadApp lists the folder and finds files A, B, C. It opens file A and starts the reading. WriteApp lists the folder and finds files A, B, C. It opens file A, sees that is is open (by an exception or whatever way) and goes to file B. ReadApp finishes file A and continues to B. It sees that it is open and continues to C. It is crucial that WriteApp doesn't write while ReadApp is reading the same file or vice versa. They are different processes.
FileChannel.lock is probably what you want.
try (
FileInputStream in = new FileInputStream(file);
java.nio.channels.FileLock lock = in.getChannel().lock();
Reader reader = new InputStreamReader(in, charset)
) {
...
}
(Disclaimer: Code not compiled and certainly not tested.)
Note the section entitled "platform dependencies" in the API doc for FileLock.
Don't use the classes in thejava.io package, instead use the java.nio package . The latter has a FileLock class. You can apply 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) {
}
If you can use Java NIO (JDK 1.4 or greater), then I think you're looking for java.nio.channels.FileChannel.lock()
FileChannel.lock()
use java.nio.channels.FileLock in conjunction with java.nio.channels.FileChannel
This may not be what you are looking for, but in the interest of coming at a problem from another angle....
Are these two Java processes that might want to access the same file in the same application? Perhaps you can just filter all access to the file through a single, synchronized method (or, even better, using JSR-166)? That way, you can control access to the file, and perhaps even queue access requests.
Use a RandomAccessFile, get it's channel, then call lock(). The channel provided by input or output streams does not have sufficient privileges to lock properly. Be sure to call unlock() in the finally block (closing the file doesn't necessarily release the lock).
Below is a sample snippet code to lock a file until it's process is done by JVM.
public static void main(String[] args) throws InterruptedException {
File file = new File(FILE_FULL_PATH_NAME);
RandomAccessFile in = null;
try {
in = new RandomAccessFile(file, "rw");
FileLock lock = in.getChannel().lock();
try {
while (in.read() != -1) {
System.out.println(in.readLine());
}
} finally {
lock.release();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Use this for unix if you are transferring using winscp or ftp:
public static void isFileReady(File entry) throws Exception {
long realFileSize = entry.length();
long currentFileSize = 0;
do {
try (FileInputStream fis = new FileInputStream(entry);) {
currentFileSize = 0;
while (fis.available() > 0) {
byte[] b = new byte[1024];
int nResult = fis.read(b);
currentFileSize += nResult;
if (nResult == -1)
break;
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("currentFileSize=" + currentFileSize + ", realFileSize=" + realFileSize);
} while (currentFileSize != realFileSize);
}

Write Lock in Java

I have a file say text.csv from which my java programs tries to read/write.
Is there a way in Java to detect if this file is opened for writing when the file has been opened by some user by "double clicking"? If so , how? I'm looking for this kind of code:
if(isOpenForWrite(File file){
//say text.csv is already opened ...
}
Any helpful documentation or other resources is welcome.
Best way to check this is checking if you can rename the file
String fileName = "C:\\Text.xlsx";
File file = new File(fileName);
// try to rename the file with the same name
File sameFileName = new File(fileName);
if(file.renameTo(sameFileName)){
// if the file is renamed
System.out.println("file is closed");
}else{
// if the file didnt accept the renaming operation
System.out.println("file is opened");
}
or use Apache Common IO library
I would use the FileChannel.lock to do this.
try { // Get a file channel for the file
File file = new File("text.csv");
FileChannel channel = new RandomAccessFile(file, "rw").getChannel();
// Blocks until it can retrieve the lock.
FileLock lock = channel.lock();
// Try acquiring the lock without blocking.
// lock is null or exception if the file is already locked.
try {
lock = channel.tryLock();
} catch (OverlappingFileLockException e){}
lock.release(); // Close the file
channel.close();
} catch (Exception e) {
}
Source : Java: Check if file is already open
Use this i found this in above commanded link
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
}

Status of a file in java

How to know the status of a file, that is, if application is blocked and it is blocking. In java, if there is an API for this or you can use Java IO.
Thank you.
If you are asking about file locks, the following example from Example Depot shows how to use it :
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();
// 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
lock.release();
// Close the file
channel.close();
} catch (Exception e) {
}

Check if a file is locked in Java

My Java program wants to read a file which can be locked by another program writing into it. I need to check if the file is locked and if so wait until it is free. How do I achieve this?
The Java program is running on a Windows 2000 server.
Should work in Windows:
File file = new File("file.txt");
boolean fileIsNotLocked = file.renameTo(file);
Under Windows with Sun's JVM, the FileLocks should work properly, although the JavaDocs leave the reliability rather vague (system dependent).
Nevertheless, if you only have to recognize in your Java program, that some other program is locking the file, you don't have to struggle with FileLocks, but can simply try to write to the file, which will fail if it is locked. You better try this on your actual system, but I see the following behaviour:
File f = new File("some-locked-file.txt");
System.out.println(f.canWrite()); // -> true
new FileOutputStream(f); // -> throws a FileNotFoundException
This is rather odd, but if you don't count platform independence too high and your system shows the same behaviour, you can put this together in a utility function.
With current Java versions, there is unfortunately no way to be informed about file state changes, so if you need to wait until the file can be written, you have to try every now and then to check if the other process has released its lock. I'm not sure, but with Java 7, it might be possible to use the new WatchService to be informed about such changes.
Use a FileLock in all the Java applications using that file and have them run within the same JVM. Otherwise, this can't be done reliably.
If multiple processes (which can be a mix of Java and non-Java) might be using the file, use a FileLock. A key to using file locks successfully is to remember that they are only "advisory". The lock is guaranteed to be visible if you check for it, but it won't stop you from doing things to the file if you forget. All processes that access the file should be designed to use the locking protocol.
You can try to get an exclusive lock on the file. As long as the exclusive lock cannot be obtained, another program has a lock (exclusive or shared) on the file.
The best way is to use FileLock, but in my case (jdk 1.6) I tried with success:
public static boolean isFileUnlocked(File file) {
try {
FileInputStream in = new FileInputStream(file);
if (in!=null) in.close();
return true;
} catch (FileNotFoundException e) {
return false;
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
I tryed combination of answers (#vlad) on windows with access to Linux Smb share and it worked for me. The first part was enough for lock like Excel but not for some editors. I added second part (rename) for testing both situations.
public static boolean testLockFile(File p_fi) {
boolean bLocked = false;
try (RandomAccessFile fis = new RandomAccessFile(p_fi, "rw")) {
FileLock lck = fis.getChannel().lock();
lck.release();
} catch (Exception ex) {
bLocked = true;
}
if (bLocked)
return bLocked;
// try further with rename
String parent = p_fi.getParent();
String rnd = UUID.randomUUID().toString();
File newName = new File(parent + "/" + rnd);
if (p_fi.renameTo(newName)) {
newName.renameTo(p_fi);
} else
bLocked = true;
return bLocked;
}
For Windows, you can also use:
new RandomAccessFile(file, "rw")
If the file is exclusively locked (by MS Word for example), there will be exception:
java.io.FileNotFoundException: <fileName> (The process cannot access the file because it is being used by another process).
This way you do not need to open/close streams just for the check.
Note - if the file is not exclusively locked (say opened in Notepad++) there will be no exception.
Improved Amjad Abdul-Ghani answer, I found that no error was produced until attempting to read from the file
public static boolean isFilelocked(File file) {
try {
try (FileInputStream in = new FileInputStream(file)) {
in.read();
return false;
}
} catch (FileNotFoundException e) {
return file.exists();
} catch (IOException ioe) {
return true;
}
}
Tested on windows only :
you can check if the file is locked as following enhanced venergiac answer:
check for (file.exist()) file exists but with FileNotFoundException means is locked!
you will notice this message (The process cannot access the file because it is being used by another process)
public static boolean isFilelocked(File file) {
try {
FileInputStream in = new FileInputStream(file);
in.close();
return false;
} catch (FileNotFoundException e) {
if(file.exist()){
return true;
}
return false;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}

How can I lock a file using java (if possible)

I have a Java process that opens a file using a FileReader. How can I prevent another (Java) process from opening this file, or at least notify that second process that the file is already opened? Does this automatically make the second process get an exception if the file is open (which solves my problem) or do I have to explicitly open it in the first process with some sort of flag or argument?
To clarify:
I have a Java app that lists a folder and opens each file in the listing for processing it. It processes each file after the other. The processing of each file consists of reading it and doing some calculations based on the contents and it takes about 2 minutes. I also have another Java app that does the same thing but instead writes on the file. What I want is to be able to run these apps at the same time so the scenario goes like this. ReadApp lists the folder and finds files A, B, C. It opens file A and starts the reading. WriteApp lists the folder and finds files A, B, C. It opens file A, sees that is is open (by an exception or whatever way) and goes to file B. ReadApp finishes file A and continues to B. It sees that it is open and continues to C. It is crucial that WriteApp doesn't write while ReadApp is reading the same file or vice versa. They are different processes.
FileChannel.lock is probably what you want.
try (
FileInputStream in = new FileInputStream(file);
java.nio.channels.FileLock lock = in.getChannel().lock();
Reader reader = new InputStreamReader(in, charset)
) {
...
}
(Disclaimer: Code not compiled and certainly not tested.)
Note the section entitled "platform dependencies" in the API doc for FileLock.
Don't use the classes in thejava.io package, instead use the java.nio package . The latter has a FileLock class. You can apply 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) {
}
If you can use Java NIO (JDK 1.4 or greater), then I think you're looking for java.nio.channels.FileChannel.lock()
FileChannel.lock()
use java.nio.channels.FileLock in conjunction with java.nio.channels.FileChannel
This may not be what you are looking for, but in the interest of coming at a problem from another angle....
Are these two Java processes that might want to access the same file in the same application? Perhaps you can just filter all access to the file through a single, synchronized method (or, even better, using JSR-166)? That way, you can control access to the file, and perhaps even queue access requests.
Use a RandomAccessFile, get it's channel, then call lock(). The channel provided by input or output streams does not have sufficient privileges to lock properly. Be sure to call unlock() in the finally block (closing the file doesn't necessarily release the lock).
Below is a sample snippet code to lock a file until it's process is done by JVM.
public static void main(String[] args) throws InterruptedException {
File file = new File(FILE_FULL_PATH_NAME);
RandomAccessFile in = null;
try {
in = new RandomAccessFile(file, "rw");
FileLock lock = in.getChannel().lock();
try {
while (in.read() != -1) {
System.out.println(in.readLine());
}
} finally {
lock.release();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Use this for unix if you are transferring using winscp or ftp:
public static void isFileReady(File entry) throws Exception {
long realFileSize = entry.length();
long currentFileSize = 0;
do {
try (FileInputStream fis = new FileInputStream(entry);) {
currentFileSize = 0;
while (fis.available() > 0) {
byte[] b = new byte[1024];
int nResult = fis.read(b);
currentFileSize += nResult;
if (nResult == -1)
break;
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("currentFileSize=" + currentFileSize + ", realFileSize=" + realFileSize);
} while (currentFileSize != realFileSize);
}

Categories