仕事でファイルを/tmpからとあるディレクトリに移動する方法でjava.io.File.renameTo()を使っていました。
でも、本番環境で適応して実行してみるとファイルが移動できず。
評価環境、開発環境では間違いなく動くのになんでだろうという状況になりました。
本番環境のログ何も出てませんでした……。
当初はシンボリックリンクが原因だろうと思い、評価及び開発環境にも本番環境と同じシンボリックリンクを張り、実行しましたが本番環境での現象が発生せず。
何が原因かわからず調べていました。
原因発覚
java.io.File.renameTo()はパーティションをまたがった移動ができないみたいです。
上記のメールが飛んできました。
早速開発環境で試すと確かにファイル移動ができない!
renameTo()は内部リンク張替だけで実データはそのままだからできないそうです。
(Windowsでは別パーティションでもrenameTo()でファイル移動はできるみたいです)
説明にも「名前の変更操作では、ファイルをファイルシステム間で移動できないことがあります。」って書いてますね。盲点でした。
対策
org.apache.commons.io.FileUtilsのmoveFileを使うことで対応ができるみたいです。(ファイルを移動先コピーしてから削除する関数のようです。)
こちらよりダウンロードできます。
//import java.io.File;
import java.io.IOException;
import org.apache.commons.io.FileUtils;
public class Test {
void main() throws IOException{
//移動元
File fromFile = new File("/tmp/test.txt");
//移動先
File toFile = new File("/home/test/test.txt");
//fromFile.renameTo(toFile);//パーティション跨げれない
FileUtils.moveFile(fromFile, toFile);//パーティション跨げる
}
}
コピーになるのでファイル容量が大きいかつ同一パーティションならばrenameToを使うほうがいいと思います。
renameTo()は戻り値がbooleanなので、戻り値がfalseの時エラーを出す処理を作った方がいいと思います。
(moveFileは戻り値がないです。)
本番適応時に不具合でるとものすごく冷や汗がでます。本番環境と同じ環境で評価、開発作らないといけないですね……教訓になりました。