With your suggestions given on this thread,
I tried using FileLock, however, when I write something in the file, somehow excel file gets corrupted and there is nothing in the file (it gets empty, no contents in there)
I have the following method:
void writeIntoTheFile(XSSFWorkbook defectWorkBook, File fileToWrite) {
FileLock lock = null;
FileChannel channel = null;
FileOutputStream out = null;
try {
//fileToWrite contains an excel .xlsx file
channel = new RandomAccessFile(fileToWrite, "rw").getChannel();
lock = channel.tryLock();
if (lock != null) {
out = new FileOutputStream(fileToWrite.getPath());
defectWorkBook.write(out);
} else {
JOptionPane.showMessageDialog(null, "Another instance is already writing, Try after a few seconds.", "Write Error...", JOptionPane.INFORMATION_MESSAGE);
}
out.close();
} catch (Exception e) {
e.getMessage();
}
finally{
if (lock != null && lock.isValid()) {
lock.release();
}
channel.close();
}
}
Seems the problem is coming from below code:
channel = new RandomAccessFile(fileToWrite, "rw").getChannel();
lock = channel.tryLock();
Can anyone please help me on this issue?
rahul
I suspect you are getting an exception in your try{} block, but your catch clock doesn't prin it. e.getMessage() will get the message but not print it.
I suggest something along the lines of e.printStackTrace() (for a production system you would want to do something more useful with the exception).
Related
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);
}
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
}
I'm reading a URL with the following code:
URL myURL = new URL("htpp://path_to_my_file");
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(myURL.openStream()));
while (reader.ready()) {
String line = reader.readLine();
...
}
} catch (IOException e) {
throw new RuntimeException("Parsing of file failed: " + myURL, e);
}
Could it happen, that the file is not read completely? (because of network problems or something else?). If yes, is there a way to test it or even to avoid?
The background: I'm working on an application (not written by me up to this point) and users report me that parts of files are missing sometimes. It happens sporadically so my only guess was that something sometimes fails when the file is read in but I have too few java-background to be sure...
Yes, you'll know it's happened when you get an IOException as per the Reader.readLine docs.
So you'll want to catch the Exception, something like this:
try {
while (reader.ready()) {
String line = reader.readLine();
}
}
catch(IOException e) {
// Bah! Humbug!
// Should really log this too. So if you're using Log4j:
log.error("Error reading from URL " + myURL.toString(), e);
} finally {
try { if (reader != null) reader.close(); }catch(Exception e){}
}
Somewhere here, I found the following comment:
ready() != has more
ready() does not indicate that there is more data to be read. It only shows if a read will could block the thread. It is likely that it will return false before you read all data.
To find out if there is no more data check if readLine() returns null
It sounds that the implementation with reader.ready() causes my problem. Am I wrong with this assumption?
Wrote up a basic file handler for a Java Homework assignment, and when I got the assignment back I had some notes about failing to catch a few instances:
Buffer from file could have been null.
File was not found
File stream wasn't closed
Here is the block of code that is used for opening a file:
/**
* Create a Filestream, Buffer, and a String to store the Buffer.
*/
FileInputStream fin = null;
BufferedReader buffRead = null;
String loadedString = null;
/** Try to open the file from user input */
try
{
fin = new FileInputStream(programPath + fileToParse);
buffRead = new BufferedReader(new InputStreamReader(fin));
loadedString = buffRead.readLine();
fin.close();
}
/** Catch the error if we can't open the file */
catch(IOException e)
{
System.err.println("CRITICAL: Unable to open text file!");
System.err.println("Exiting!");
System.exit(-1);
}
The one comment I had from him was that fin.close(); needed to be in a finally block, which I did not have at all. But I thought that the way I have created the try/catch it would have prevented an issue with the file not opening.
Let me be clear on a few things: This is not for a current assignment (not trying to get someone to do my own work), I have already created my project and have been graded on it. I did not fully understand my Professor's reasoning myself. Finally, I do not have a lot of Java experience, so I was a little confused why my catch wasn't good enough.
Buffer from file could have been null.
The file may be empty. That is, end-of-file is reach upon opening the file. loadedString = buffRead.readLine() would then have returned null.
Perhaps you should have fixed this by adding something like if (loadedString == null) loadedString = "";
File was not found
As explained in the documentation of the constructor of FileInputStream(String) it may throw a FileNotFoundException. You do catch this in your IOException clause (since FileNotFoundException is an IOException), so it's fine, but you could perhaps have done:
} catch (FileNotFoundException fnfe) {
System.err.println("File not fonud!");
} catch (IOException ioex {
System.err.println("Some other error");
}
File stream wasn't closed
You do call fin.close() which in normal circumstances closes the file stream. Perhaps he means that it's not always closed. The readLine could potentially throw an IOException in which case the close() is skipped. That's the reason for having it in a finally clause (which makes sure it gets called no matter what happens in the try-block. (*)
(*) As #mmyers correctly points out, putting the close() in a finally block will actually not be sufficient since you call System.exit(-1) in the catch-block. If that really is the desired behavior, you could set an error flag in the catch-clause, and exit after the finally-clause if this flag is set.
But what if your program threw an exception on the second or third line of your try block?
buffRead = new BufferedReader(new InputStreamReader(fin));
loadedString = buffRead.readLine();
By this point, a filehandle has been opened and assigned to fin. You could trap the exception but the filehandle would remain open.
You'll want to move the fin.close() statement to a finally block:
} finally {
try {
if (fin != null) {
fin.close();
}
} catch (IOException e2) {
}
}
Say buffRead.readLine() throws an exception, will your FileInputStream ever be closed, or will that line be skipped? The purpose of a finally block is that even in exceptional circumastances, the code in the finally block will execute.
There are a lot of other errors which may happen other than opening the file.
In the end you may end up with a fin which is defined or not which you have to protect against null pointer errors, and do not forget that closing the file can throw a new exception.
My advice is to capture this in a separate routine and let the IOExceptions fly out of it :
something like
private String readFile() throws IOException {
String s;
try {
fin = new FileInputStream(programPath + fileToParse);
buffRead = new BufferedReader(new InputStreamReader(fin));
s = buffRead.readLine();
fin.close();
} finally {
if (fin != null {
fin.close()
}
}
return s
}
and then where you need it :
try {
loadedString = readFile();
} catch (IOException e) {
// handle issue gracefully
}
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);
}