4

I have a implemented a listener that notifies if we receive a new file in a particular directory. This is implemented by polling and using a TimerTask. Now the program is so set up that once it receives a new file it calls another java program that opens the file and validates whether it is the correct file. My problem is that since the polling happens a specified number of seconds later there can arise a case in which a file is being copied in that directory and hence is locked by windows.

This throws an IOException since the other java program that tries to open it for validation cannot ("File is being used by another process").

Is there a way I can know when windows has finished copying and then call the second program to do the validations from java?

I will be more than happy to post code snippets if someone needs them in order to help.

Thanks

Eosphorus
  • 312
  • 3
  • 10
  • 19

3 Answers3

5

Thanks a lot for all the help, I was having the same problem with WatchEvent. Unfortunately, as you said, file.canRead() and file.canWrite() both return true, even if the file still locked by Windows. So I discovered that if I try to "rename" it with the same name, I know if Windows is working on it or not. So this is what I did:

    while(!sourceFile.renameTo(sourceFile)) {
        // Cannot read from file, windows still working on it.
        Thread.sleep(10);
    }
jfajunior
  • 1,211
  • 1
  • 15
  • 19
  • 1
    thats a good workaround @jfajunior. I did it in a similar manner. I simply tried to open the file and it would give an exception because windows was working on it. So I caught the exception put the thread to sleep like you and tried again after an exponential loop as was suggested above. Glad this post helped you – Eosphorus Mar 21 '13 at 21:08
3

This one is a bit tricky. It would have been a piece of cake if you could control or at least communicate with the program copying the file but this won't be possible with Windows I guess. I had to deal with a similar problem a while ago with SFU software, I resolved it by looping on trying to open the file for writing until it becomes available.

To avoid high CPU usage while looping, checking the file can be done at an exponential distribution rate.

EDIT A possible solution:

File fileToCopy = File(String pathname);
int sleepTime = 1000; // Sleep 1 second
while(!fileToCopy .canWrite()){
    // Cannot write to file, windows still working on it
    Sleep(sleepTime);
    sleepTime *= 2; // Multiply sleep time by 2 (not really exponential but will do the trick)
    if(sleepTime > 30000){ 
        // Set a maximum sleep time to ensure we are not sleeping forever :)
        sleepTime = 30000;
    }
}
// Here, we have access to the file, go process it
processFile(fileToCopy);
GETah
  • 20,922
  • 7
  • 61
  • 103
  • This sounds like a valid option.Could you give a small example code as to how I may implement an exponential loop if it fails trying to open the file? – Eosphorus Dec 01 '11 at 16:51
  • This works. Thanks a lot. However the filetoCopy.canWrite() or filetoCopy.canRead() will always be true even if windows has a lock. So we need to try opening the file and catch the exception instead of the while loop. Thanks again and I will mark this resolved – Eosphorus Dec 01 '11 at 19:59
  • @user1074440 Glad it worked :) fileToCopy.canWrite() should return false if the file is open by another process. But your suggestion should (and the one I suggested in top of the answer) should do the work. Always a pleasure to help :) – GETah Dec 01 '11 at 20:17
  • ya I know but I have no idea why it kept returning true even when the file was open but later gave an error when the other java program tried to open it. havezx was suggesting the canRead() option. But I was able to implement your code by using a try catch block in a while loop to keep checking till the file can be open. Its not the best practice using a catch block to write code but it worked :D – Eosphorus Dec 01 '11 at 22:04
  • @Eosphorus Files can be opened in different modes, including with or without exclusive access. Programming languages usually support in their "open file" statement syntax some clauses to set the opening mode. Try to open a text file in Notepad, and while it's open open it also in MS Word. Try to save the file in Notepad and you will get an error that the file is used by another process. Try to save it in Word and it will be saved as expected. It's because Notepad and Word are opening the file in different modes. My guess is that `canRead()` and `canWrite()` are based on the opening mode. – SantiBailors Sep 13 '16 at 07:38
0

I think you can create the File object and then use canRead or canWrite to know whether file ready to be used by the other java program.

http://docs.oracle.com/javase/6/docs/api/java/io/File.html

Other option is to try to Open file on first program and if it throws the exception then dont call the other java program. But I ll recommend the above 'File option.

havexz
  • 9,550
  • 2
  • 33
  • 29
  • 2
    the canRead actually does not say whether the file is ready to be used by another program. I tried using it while the file was in the process of being copied but strangely enough the value returned true when I was expecting a false since the file was locked by windows. – Eosphorus Dec 01 '11 at 16:05
  • but you should try `canWrite` – havexz Dec 02 '11 at 07:24