現在、私はそのルーチンの1つでソースディレクトリからのファイルを処理するプロジェクトに取り組んでいます。 Javaプロセスがあり、指定されたディレクトリを検索し、ファイルが存在する場合はファイルを読み取って処理しようとします。ファイルは非常に大きく、他のサードパーティプロセスによって更新されます。問題は、ファイルがは完全に書かれていますか?file.length()
を使用しようとしていますが、書き込みプロセスが完了していない場合でも実際のサイズが返されるように見えます。ソリューションはプラットフォームに依存する必要があると感じています。 。
更新:この質問は重複と実際に違いはありませんが、評価の高い実際のコードスニペットで回答があります。
プロデューサープロセスは、書き込みが終了したときにファイルを閉じますか?その場合、プロデューサープロセスがまだプロデュースしていると、コンシューマープロセスでファイルを排他ロックで開こうとしても失敗します。
私はソリューションを機能させました:
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解決策が私にとって望ましいです。
追伸最初はFileOutputStream
ではなくRandomAccessFile
を使用しましたが、書き込み中のファイルがロックされました。
Windowsのこのシナリオで過去に使用した簡単な解決策の1つは、boolean File.renameTo(File)
を使用して、元のファイルを別のステージングフォルダーに移動することです。
boolean success = potentiallyIncompleteFile.renameTo(stagingAreaFile);
success
がfalse
の場合、potentiallyIncompleteFile
はまだ書き込まれています。
そのための一般的な解決策はないと思います。一部のアプリケーションは書き込み呼び出しの前にファイルサイズを設定できるため、ファイルサイズの検索は間違っています。可能性の1つは、ロックを使用することです。これには、ライターが書き込みロック(または排他ロック)を獲得する必要があります。ライターを変更できない場合は、Linuxのフューザーなど、OSが提供するツールを使用して、ファイルにアクセスするプロセスがまだあるかどうかを確認できます。
このコードを単一のプラットフォームで使用する場合は、 NIOのFileLock機能 を使用できる場合があります。ただし、ドキュメントを注意深く読んでください。多くのプラットフォームでは、ロックは助言にすぎません。
別のアプローチは、1つのプロセスにプロセスが認識できない名前でファイルを書き込んでから、書き込みが完了したときにファイルを認識可能な名前に変更することです。ほとんどのプラットフォームでは、ソースと宛先が同じファイルシステムボリュームである場合、名前変更操作はアトミックです。
Java 1.7を使用できる場合は、NIOツール、特に Java.nio.channels.FileChannel を見てください。
here は、ファイルをロックして読み取る例です。