Detect File Closure

Hi all,

In my app, users can view and modify files that are stored in the database. This is achieved by getting a byte[] from the DB, writing the file to a temp directory, and then opening with ProcessBuilder or Runtime.exec() ("cmd /c [file path]"). That part's ok.

The issue is that I need to determine when the FILE is closed - not the application that opened the file. This is because if for example Word is started to open a .doc file, the user may make changes to the file and close it, but not close Word, in which case my Java app (if using Process.waitFor()) would still be waiting for the Word process to exit.

I have can monitor the file for changes (lastModified), but this doesn't necessarily mean that the file is closed - just that it's changed.

Upon the file closing I need to automatically rewrite the document to the database, and delete the temp file.

Any thoughts on how to detect closure of the file would be greatly appreciated.

Thanks,

Paul C.

[1018 byte] By [Pcasanovaa] at [2007-10-3 3:24:42]
# 1

You can't detect file closures from other processes, that would be a very unsafe way to synchronize changes between multiple processes, but you can certainly check if a file has been locked. Your application should also be aquiring a lock on the file while you are writting out its contents, just incase another user/process tries to modify the temp file in a middle of your DB update.

See java.nio.channels.FileChannel.tryLock and FileChannel.lock.

voytechsa at 2007-7-14 21:17:29 > top of Java-index,Core,Core APIs...
# 2
You are a genius.Thank you.
Pcasanovaa at 2007-7-14 21:17:29 > top of Java-index,Core,Core APIs...
# 3

For anyone interested, here is the code that finally got it all working:

public void run()

{

try

{

// Write the blob to the selected file

FileOutputStream fos = new FileOutputStream(tempFile);

fos.write(sysGenArtifactData.getArtifactData());

fos.flush();

fos.close();

fos = null;

}

catch (FileNotFoundException ex)

{

logger.error(ex);

}

catch (IOException ex)

{

logger.error(ex);

}

ProcessBuilder processBuilder;

Process process;

try

{

// Assemble the startup command

ArrayList<String> list = new ArrayList<String>();

list.add("cmd");

list.add("/c");

list.add("\"" + tempFile.getAbsolutePath() + "\"");

if (logger.isDebugEnabled()) logger.debug(tempFile.getAbsolutePath());

// Initialise the process builder

processBuilder = new ProcessBuilder(list);

processBuilder.directory(tempFile.getParentFile());

// Start the process

process = processBuilder.start();

waitForFileClosure();

if (autoSave)

{

autoSave(tempFile);

}

if (!tempFile.delete())

{

tempFile.deleteOnExit();

}

}

catch (IOException ioe)

{

ioe.printStackTrace();

}

catch (Exception e)

{

e.printStackTrace();

}

}

private void waitForFileClosure()

{

while(FileUtilities.isFileOpen(tempFile))

{

if (logger.isDebugEnabled()) logger.debug("Waiting for file to be closed: " + tempFile.getAbsolutePath());

ThreadUtilities.waitSeconds(30);

}

if (logger.isDebugEnabled()) logger.debug("File closed: " + tempFile.getAbsolutePath());

}

}

public static boolean isFileOpen(File file)

{

if (logger.isDebugEnabled()) logger.debug("Attempting to aquire file lock on " + file.getAbsolutePath());

boolean isFileOpen = false;

RandomAccessFile raf = null;

FileLock lock = null;

try

{

raf = new RandomAccessFile(file.getAbsolutePath(), "rw");

lock = raf.getChannel().tryLock();

if (lock == null)

{

isFileOpen = true;

}

else

{

lock.release();

}

}

catch (FileNotFoundException ex)

{

isFileOpen = true;

}

catch (IOException ex)

{

isFileOpen = true;

}

finally

{

if (raf != null)

{

try

{

raf.close();

raf = null;

}

catch (IOException ex)

{

logger.error(ex);

}

}

}

if (logger.isDebugEnabled()) logger.debug("File open status for " + file.getAbsolutePath() + ": " + isFileOpen);

return isFileOpen;

}

Thanks to everyone for their help,

Paul C.

Pcasanovaa at 2007-7-14 21:17:29 > top of Java-index,Core,Core APIs...