nit*_*ite 28 java directory watch
我一直在编写一个监视目录的程序,当在其中创建文件时,它会更改名称并将它们移动到新目录.在我的第一个实现中,我使用了Java的Watch Service API,当我测试1kb文件时,它运行良好.出现的问题是,实际上创建的文件是50-300mb.当发生这种情况时,观察者API会立即找到该文件,但由于它仍在被写入,因此无法移动它.我尝试将观察者放在循环中(生成异常,直到文件可以移动),但这看起来效率很低.
由于这不起作用,我尝试使用定时器,每隔10秒检查一次文件夹,然后尽可能移动文件.这是我最终选择的方法.
问题:无论如何在没有进行异常检查或不断比较大小的情况下发出文件写入信号?我喜欢为每个文件使用Watcher API一次,而不是使用计时器不断检查(并运行异常).
所有回复都非常感谢!
NT
Jas*_*man 20
我今天遇到了同样的问题.我在实际导入文件之前使用了一小段延迟并不是一个大问题,我仍然想使用NIO2 API.我选择的解决方案是等待文件在10秒内没有被修改,然后对其执行任何操作.
实施的重要部分如下.程序等待,直到等待时间到期或发生新事件.每次修改文件时都会重置到期时间.如果在等待时间到期之前删除文件,则会从列表中删除该文件.我使用poll方法的预期到期时间超时,即(lastmodified + waitTime)-currentTime
private final Map<Path, Long> expirationTimes = newHashMap();
private Long newFileWait = 10000L;
public void run() {
for(;;) {
//Retrieves and removes next watch key, waiting if none are present.
WatchKey k = watchService.take();
for(;;) {
long currentTime = new DateTime().getMillis();
if(k!=null)
handleWatchEvents(k);
handleExpiredWaitTimes(currentTime);
// If there are no files left stop polling and block on .take()
if(expirationTimes.isEmpty())
break;
long minExpiration = min(expirationTimes.values());
long timeout = minExpiration-currentTime;
logger.debug("timeout: "+timeout);
k = watchService.poll(timeout, TimeUnit.MILLISECONDS);
}
}
}
private void handleExpiredWaitTimes(Long currentTime) {
// Start import for files for which the expirationtime has passed
for(Entry<Path, Long> entry : expirationTimes.entrySet()) {
if(entry.getValue()<=currentTime) {
logger.debug("expired "+entry);
// do something with the file
expirationTimes.remove(entry.getKey());
}
}
}
private void handleWatchEvents(WatchKey k) {
List<WatchEvent<?>> events = k.pollEvents();
for (WatchEvent<?> event : events) {
handleWatchEvent(event, keys.get(k));
}
// reset watch key to allow the key to be reported again by the watch service
k.reset();
}
private void handleWatchEvent(WatchEvent<?> event, Path dir) throws IOException {
Kind<?> kind = event.kind();
WatchEvent<Path> ev = cast(event);
Path name = ev.context();
Path child = dir.resolve(name);
if (kind == ENTRY_MODIFY || kind == ENTRY_CREATE) {
// Update modified time
FileTime lastModified = Attributes.readBasicFileAttributes(child, NOFOLLOW_LINKS).lastModifiedTime();
expirationTimes.put(name, lastModified.toMillis()+newFileWait);
}
if (kind == ENTRY_DELETE) {
expirationTimes.remove(child);
}
}
Run Code Online (Sandbox Code Playgroud)
sta*_*ker 11
写另一个文件作为原始文件完成的指示.如果完成创建文件'fileorg.done'并仅检查'fileorg.done',则Ig'fileorg.dat'正在增长.
通过巧妙的命名约定,您不应该遇到问题.
小智 5
我知道这是一个老问题,但也许它可以帮助别人。
我遇到了同样的问题,所以我做了以下事情:
if (kind == ENTRY_CREATE) {
System.out.println("Creating file: " + child);
boolean isGrowing = false;
Long initialWeight = new Long(0);
Long finalWeight = new Long(0);
do {
initialWeight = child.toFile().length();
Thread.sleep(1000);
finalWeight = child.toFile().length();
isGrowing = initialWeight < finalWeight;
} while(isGrowing);
System.out.println("Finished creating file!");
}
Run Code Online (Sandbox Code Playgroud)
当文件被创建时,它会变得越来越大。所以我所做的就是比较一秒之间的重量。应用程序将一直循环,直到两个权重相同。
小智 5
看起来 Apache Camel 通过尝试重命名文件 (java.io.File.renameTo) 来处理文件未完成上传问题。如果重命名失败,则没有读锁,但继续尝试。当重命名成功时,他们将其重命名,然后继续进行预期的处理。
请参阅下面的operations.renameFile。以下是 Apache Camel 源的链接: GenericFileRenameExclusiveReadLockStrategy.java和FileUtil.java
public boolean acquireExclusiveReadLock( ... ) throws Exception {
LOG.trace("Waiting for exclusive read lock to file: {}", file);
// the trick is to try to rename the file, if we can rename then we have exclusive read
// since its a Generic file we cannot use java.nio to get a RW lock
String newName = file.getFileName() + ".camelExclusiveReadLock";
// make a copy as result and change its file name
GenericFile<T> newFile = file.copyFrom(file);
newFile.changeFileName(newName);
StopWatch watch = new StopWatch();
boolean exclusive = false;
while (!exclusive) {
// timeout check
if (timeout > 0) {
long delta = watch.taken();
if (delta > timeout) {
CamelLogger.log(LOG, readLockLoggingLevel,
"Cannot acquire read lock within " + timeout + " millis. Will skip the file: " + file);
// we could not get the lock within the timeout period, so return false
return false;
}
}
exclusive = operations.renameFile(file.getAbsoluteFilePath(), newFile.getAbsoluteFilePath());
if (exclusive) {
LOG.trace("Acquired exclusive read lock to file: {}", file);
// rename it back so we can read it
operations.renameFile(newFile.getAbsoluteFilePath(), file.getAbsoluteFilePath());
} else {
boolean interrupted = sleep();
if (interrupted) {
// we were interrupted while sleeping, we are likely being shutdown so return false
return false;
}
}
}
return true;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
17077 次 |
| 最近记录: |