How to wait on file creation

10,161

Solution 1

A better way is to write the file to a temporary file name like myscript.pl.tmp and rename it when you are finished. As rename is atomic, you won't see it in an incomplete state.

BTW You can use the WatchService to be notified when a file appears. Watching a Directory for Changes

Solution 2

As @peter-lawrey has mentioned, the correct way to go is java.nio.file.WatchService.

The following is a simple implementation for the specific (but common) case of waiting the creation of a file. This static method returns the basic file attributes of the target file (creationTime is among them), or null if the file did not show up.

public static BasicFileAttributes awaitFile(Path target, long timeout) 
    throws IOException, InterruptedException
{
    final Path name = target.getFileName();
    final Path targetDir = target.getParent();

    // If path already exists, return early
    try {
        return Files.readAttributes(target, BasicFileAttributes.class);
    } catch (NoSuchFileException ex) {}

    final WatchService watchService = FileSystems.getDefault().newWatchService();
    try {
        final WatchKey watchKey = targetDir.register(watchService, StandardWatchEventKinds.ENTRY_CREATE);
        // The file could have been created in the window between Files.readAttributes and Path.register
        try {
            return Files.readAttributes(target, BasicFileAttributes.class);
        } catch (NoSuchFileException ex) {}
        // The file is absent: watch events in parent directory 
        WatchKey watchKey1 = null;
        boolean valid = true;
        do {
            long t0 = System.currentTimeMillis();
            watchKey1 = watchService.poll(timeout, TimeUnit.MILLISECONDS);
            if (watchKey1 == null) {
                return null; // timed out
            }
            // Examine events associated with key
            for (WatchEvent<?> event: watchKey1.pollEvents()) {
                Path path1 = (Path) event.context();
                if (path1.getFileName().equals(name)) {
                    return Files.readAttributes(target, BasicFileAttributes.class);
                }
            }
            // Did not receive an interesting event; re-register key to queue
            long elapsed = System.currentTimeMillis() - t0;
            timeout = elapsed < timeout? (timeout - elapsed) : 0L;
            valid = watchKey1.reset();
        } while (valid);
    } finally {
        watchService.close();
    }

    return null;
}
Share:
10,161
chenino
Author by

chenino

Small coding intern and student

Updated on June 04, 2022

Comments

  • chenino
    chenino almost 2 years

    My situation is as following: I got a Java program, wich starts a perl script. The Perl script is generating a file, on which Java should continue working. As by now, i had set a

    Thread.sleep(3000);
    

    to let Java wait for the file to be finished. I was looking for an more elegant way to let Java check if the file exists and continue then. My last try was

    Boolean waitforfile = true;  
    while(waitforfile){
           File f = new File(pathtofile);
           if(f.exists() && !f.isDirectory()) { waitforfile=false; }
           } 
    

    But that one will get me stuck in a never ending loop. Is there any way else to do it?

    Update : On Suggestion, tried, process,WaitFor(); In

        public static String syscall(String call){
        String out = "";
        try {
        String line;
        Process p = Runtime.getRuntime().exec(call);
        BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
        while ((line = input.readLine()) != null) {
          out=out+"\n"+line;
        }
        input.close();
        p.waitFor();
        } catch (Exception e) {
            System.out.println(e);
        }
    
        return out;
    }
    

    This one did not wait on my perl process to be closed.