目前我正在开发一个项目,该项目在其中一个例程中处理源目录中的文件。有一个Java进程正在查找指定的目录,并尝试读取和处理文件(如果存在)。文件退出大,并由其他第三方进程更新。问题是如何检查文件是否完整写入?我正在尝试使用file.length()
但看起来即使写入过程尚未完成它也会返回实际大小。我觉得解决方案应该依赖于平台。任何帮助将不胜感激。
更新: 这个问题与副本没有什么不同,但它有一个得到高度评价的工作代码片段的答案。
答案 0 :(得分:18)
我得到了解决方案:
private boolean isCompletelyWritten(File file) {
RandomAccessFile stream = null;
try {
stream = new RandomAccessFile(file, "rw");
return true;
} catch (Exception e) {
log.info("Skipping file " + file.getName() + " for this iteration due it's not completely written");
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
log.error("Exception during closing file " + file.getName());
}
}
}
return false;
}
感谢@cklab和@Will以及其他建议以“独家锁定”方式查看的人。我刚刚在这里发布代码,让其他人对使用它感兴趣。我相信@tigran建议的重命名解决方案也适用,但纯Java解决方案对我来说更合适。
P.S。最初我使用FileOutputStream
而不是RandomAccessFile
,但它会锁定正在写入的文件。
答案 1 :(得分:10)
生成器进程在完成写入后是否会关闭文件?如果是这样,如果生产者进程仍在生成,则尝试使用独占锁打开使用者进程中的文件将失败。
答案 2 :(得分:3)
我认为没有一个通用的解决方案。查找文件大小是错误的,因为某些应用程序可以在任何写入调用之前设置文件大小。其中一种可能性是使用锁定。这将要求writer编写一个写锁(或独占锁)。如果你不能修改编写器,那么你可以使用操作系统提供的工具,比如Linux上的fuser,看看有没有一个进程仍然访问该文件。
答案 3 :(得分:3)
我过去在Windows中使用的一个简单解决方案是使用boolean File.renameTo(File)
并尝试将原始文件移动到单独的暂存文件夹中:
boolean success = potentiallyIncompleteFile.renameTo(stagingAreaFile);
如果success
为false
,则potentiallyIncompleteFile
仍在写入。
答案 4 :(得分:2)
如果您打算在单一平台上使用此代码,则可以使用NIO's FileLock facility。但请仔细阅读文档,并注意在许多平台上,锁只是建议性的。
另一种方法是让一个进程使用您的进程无法识别的名称写入文件,然后在写入完成时将文件重命名为可识别的名称。在大多数平台上,如果源和目标是相同的文件系统卷,则重命名操作是原子操作。
答案 5 :(得分:1)
如果您可以使用Java 1.7,请查看NIO工具,特别是java.nio.channels.FileChannel
here是锁定文件并阅读文件的示例。