如何判断文件何时完成"完成"复制到观看的目录?

时间:2013-07-29 20:27:05

标签: java file path

我正在使用WatchService API来查看目录,并在用户开始将文件复制到目录中时获取ENTRY_CREATE个事件。我正在使用的文件可能很大,我想知道副本何时完成。是否有可用于实现此目的的内置java API,或者我最好只是跟踪创建的文件的大小并在大小停止增长时开始处理?

编辑:这是我的示例代码:

package com.example;

import java.io.File;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;

public class Monitor {
    public static void main(String[] args) {
        try {
            String path = args[0];

            System.out.println(String.format( "Monitoring %s", path  ));
            WatchService watcher = FileSystems.getDefault().newWatchService();
            Path watchPath = FileSystems.getDefault().getPath(path);

            watchPath.register(watcher, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_MODIFY);

            while (true) {
                WatchKey key = watcher.take();
                for (WatchEvent<?> event: key.pollEvents()) {
                    Object context = event.context();
                    System.out.println( String.format( "Event %s, type %s", context, event.kind() ));

                }
            }

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

生成此输出:

Monitoring /Users/ericcobb/Develop/watch
Event .DS_Store, type ENTRY_MODIFY
Event 7795dab5-71b1-4b78-952f-7e15a2f39801-84f3e5daeca9435aa886fbebf7f8bd61_4.mp4, type ENTRY_CREATE

7 个答案:

答案 0 :(得分:10)

创建条目后,您将收到ENTRY_CREATE个事件。对于每次后续修改,您都会收到ENTRY_MODIFY个事件。复制完成后,系统会通过ENTRY_MODIFY通知您。

答案 1 :(得分:2)

  • 我认为最常见的方法是将文件复制到同一分区上的临时目录中,然后通过原子移动命令将其移动到受监控目录。
  • 也许通过使用文件时间戳来实现解决方案

然而,这两种解决方案都需要在写作应用程序中实现。我认为你无法从阅读申请中确切地说出来。

答案 2 :(得分:2)

这是我们今天使用的库:

https://github.com/levelsbeyond/jpoller

它是原始作者不再维护的开源项目的分支。我们已经修复了一些错误,现在可以在生产中使用它。

它的工作原理是检查目录中文件的大小,并在文件大小停止增长一段时间后认为文件已完成(准备处理)。

答案 3 :(得分:2)

确保没有其他进程再写入文件的唯一有效选项是成功获取文件的写锁定。虽然有点笨拙,但您可以使用FileChannelFileLock来实现此目的

try(FileChannel ch = FileChannel.open(p, StandardOpenOption.WRITE);
    FileLock lock = ch.tryLock()){

    if(lock == null) {
        //no lock, other process is still writing            
    } else {
        //you got a lock, other process is done writing
    }
 } catch (IOException e) {
     //something else went wrong
 }

您也可以使用ch.lock()获取锁定,这是一个阻止调用。但是,由于在写入文件时会不断生成ENTRY_MODIFY事件,因此您也可以使用tryLock并等待下一个事件。

答案 4 :(得分:0)

也许你可以通过尝试获取文件的写访问权来判断,但这取决于两个因素并需要研究:

  1. 编写应用程序必须获取对文件的独占写入权限,并且在文件实际完成之前不得关闭该文件。
  2. 必须可以从Java进行测试。我会试一试,如果文件仍然被另一个程序写入而被锁定,那么WRITE访问的opening the file as FileChannel是否会引发异常。不幸的是,Javadoc没有详细说明这一点。

答案 5 :(得分:0)

如果有控制文件写入的能力,则可以写入临时文件,然后将其重命名为目标文件。那应该生成一个ENTRY_MODIFY。

类似的东西:

var myPromise;
var myList = [];
for (let i = 1; i <= 20; i++) {
  myPromise = new Promise(function(resolve, reject) {
    resolve("ITEM " + i);
  });
  myList.push(myPromise);
}
Promise.all(myList).then(function(values) {
  console.log(values);
});

console.log("End");

我建议在收到通知后等待几个MS,以等待移动完成。

答案 6 :(得分:-1)

File file = child.toAbsolutePath().toFile();
if(file.isFile() && file.isWrite())
{
}

也许这会找到你想要的东西,但不能在while语句中找到。

当您真正访问文件时,它将起作用。