Java 如何等待文件创建

Java 如何等待文件创建,java,file,io,Java,File,Io,我的情况如下: 我有一个Java程序,它启动了一个perl脚本。 Perl脚本正在生成一个文件,Java应该在该文件上继续工作。 到现在为止,我已经定下了一个目标 Thread.sleep(3000); 让Java等待文件完成。 我正在寻找一种更优雅的方法,让Java检查文件是否存在,然后继续。我最后一次尝试是 Boolean waitforfile = true; while(waitforfile){ File f = new File(pathtofile);

我的情况如下: 我有一个Java程序,它启动了一个perl脚本。 Perl脚本正在生成一个文件,Java应该在该文件上继续工作。 到现在为止,我已经定下了一个目标

Thread.sleep(3000);
让Java等待文件完成。 我正在寻找一种更优雅的方法,让Java检查文件是否存在,然后继续。我最后一次尝试是

Boolean waitforfile = true;  
while(waitforfile){
       File f = new File(pathtofile);
       if(f.exists() && !f.isDirectory()) { waitforfile=false; }
       } 
但这会让我陷入一个永无止境的循环。 还有别的办法吗

更新: 根据建议、尝试、处理、等待(); 在


这一个没有等待我的perl进程关闭。

更好的方法是将文件写入一个临时文件名,如
myscript.pl.tmp
,完成后重命名它。因为重命名是原子的,所以您不会看到它处于不完整状态


顺便说一句,您可以使用WatchService在文件出现时收到通知

正如@peter lawrey所提到的,正确的方法是
java.nio.file.WatchService

以下是等待创建文件的特定(但常见)情况的简单实现。此静态方法返回目标文件的基本文件属性(
creationTime
就是其中之一),如果文件未显示,则返回
null

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;
}
公共静态基本文件(路径目标,长超时)
抛出IOException、InterruptedException
{
最终路径名=target.getFileName();
最终路径targetDir=target.getParent();
//如果路径已经存在,请提前返回
试一试{
返回Files.readAttributes(target,BasicFileAttributes.class);
}catch(NoSuchFileException ex){}
final WatchService WatchService=FileSystems.getDefault().newWatchService();
试一试{
final WatchKey WatchKey=targetDir.register(watchService,StandardwatchEventTypes.ENTRY\u CREATE);
//该文件可能是在Files.readAttributes和Path.register之间的窗口中创建的
试一试{
返回Files.readAttributes(target,BasicFileAttributes.class);
}catch(NoSuchFileException ex){}
//文件不存在:在父目录中监视事件
WatchKey watchKey1=null;
布尔有效=真;
做{
长t0=System.currentTimeMillis();
watchKey1=watchService.poll(超时,时间单位为毫秒);
如果(watchKey1==null){
返回null;//超时
}
//检查与密钥关联的事件
for(WatchEvent事件:watchKey1.pollEvents()){
路径path1=(路径)event.context();
if(path1.getFileName().equals(name)){
返回Files.readAttributes(target,BasicFileAttributes.class);
}
}
//未收到有趣的事件;请将密钥重新注册到队列
长时间运行=System.currentTimeMillis()-t0;
超时=经过<超时?(超时-经过):0L;
valid=watchKey1.reset();
}有效期;
}最后{
watchService.close();
}
返回null;
}

为什么不等待perl进程完成呢?我必须承认,我真的不知道如何使用JavaRuntime中的Runtime.exec来等待它。exec()返回一个进程。进程有一个waitFor()方法:嗯,好吧,似乎是关于我的系统调用或者我的perl有问题,因为我在等待一段时间now@JBNizet:更新了问题嗯,我不完全确定我是否真的得到了你答案的第一部分。你的意思是我应该使用上面的代码,只需将perl脚本更改为写入一个临时文件,然后重命名它?@chenino使用重命名是表示文件已完成的有效方法。另一种方法是,如果您是启动perl脚本的人,则等待它完成。现在我们来看看WatchService
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;
}