我正在观看传入文件的目录(使用来自apache commons的FileAlterationObserver)。
class Example implements FileAlterationListener {
public void prepare() {
File directory = new File("/tmp/incoming");
FileAlterationObserver observer = new FileAlterationObserver(directory);
observer.addListener(this);
FileAlterationMonitor monitor = new FileAlterationMonitor(10);
monitor.addObserver(observer);
monitor.start();
// ...
}
public void handleFile(File f) {
// FIXME: this should be called when the writes that
// created the file have completed, not before
}
public void onFileCreate(File f) {
handleFile(f);
}
public void onFileChange(File f) {
handleFile(f);
}
}
文件由我无法控制的进程写入。
我对该代码的问题是在最初创建文件时触发了我的回调。我需要它来在文件被更改并且对文件的写入完成时触发。 (可能通过检测文件停止更改时间)
最好的方法是什么?
答案 0 :(得分:7)
我有类似的问题。起初我以为我可以使用FileWatcher服务,但它不能在远程卷上工作,我不得不通过网络安装的驱动器监控传入的文件。
然后我想我可以在一段时间内监视文件大小的变化,并在文件大小稳定后考虑文件完成(如fmucar建议的那样)。但我发现在大型文件的某些情况下,托管系统会报告它正在复制的文件的完整大小,而不是它写入磁盘的字节数。这当然使文件看起来稳定,我的探测器会在文件处理过程中捕获文件。
我最终能够通过使用FileInputStream异常使监视器工作,该异常在检测文件是否被写入时非常有效,即使文件位于网络安装的驱动器上也是如此。
long oldSize = 0L;
long newSize = 1L;
boolean fileIsOpen = true;
while((newSize > oldSize) || fileIsOpen){
oldSize = this.thread_currentFile.length();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
newSize = this.thread_currentFile.length();
try{
new FileInputStream(this.thread_currentFile);
fileIsOpen = false;
}catch(Exception e){}
}
System.out.println("New file: " + this.thread_currentFile.toString());
答案 1 :(得分:2)
从“消费者”端看来,这个问题的通用解决方案似乎是不可能的。 “生产者”可以暂时关闭该文件,然后继续追加该文件。或者“生产者”可能会崩溃,在文件系统中留下不完整的文件。
合理的模式是让“生产者”写入不受“消费者”监控的临时文件。完成写入后,将文件重命名为“消费者”实际监控的内容,此时“消费者”将获取完整的文件。
答案 2 :(得分:1)
除非您有一些文件系统限制和保证,否则我认为您无法实现所需。例如,如果您有以下情况怎么办?
如果文件X在写出后无法更新,则可以有一个执行线程来计算从上次更新到现在的经过时间,并在一段时间后确定文件写入完成。但即使这样也有问题。如果文件系统挂起,并且写入没有发生一段时间,您可能会错误地断定该文件已完成写出。
答案 3 :(得分:1)
您可以在几秒钟内检查文件的大小2次或更多次,如果大小没有变化,那么您可以决定文件更改已完成并继续执行。
答案 4 :(得分:0)
如果您使用FileAlterationListener并添加FileAlterationListenerAdaptor,则可以实施所需的方法并使用FileAlterationMonitor监控文件......
public static void main( String[] args ) throws Exception {
FileAlterationObserver fao = new FileAlterationObserver( dir );
final long interval = 500;
FileAlterationMonitor monitor = new FileAlterationMonitor( interval );
FileAlterationListener listener = new FileAlterationListenerAdaptor() {
@Override
public void onFileCreate( File file ) {
try {
System.out.println( "File created: " + file.getCanonicalPath() );
} catch( IOException e ) {
e.printStackTrace( System.err );
}
}
@Override
public void onFileDelete( File file ) {
try {
System.out.println( "File removed: " + file.getCanonicalPath() );
} catch( IOException e ) {
e.printStackTrace( System.err );
}
}
@Override
public void onFileChange( File file ) {
try {
System.out.println( file.getName() + " changed: ");
} catch( Exception e ) {
e.printStackTrace();
}
}
};
// Add listeners...
fao.addListener( listener );
monitor.addObserver( fao );
monitor.start();
}