File.renameToメソッドとは
java.io.File.renameToメソッドは、ファイルの移動を行うメソッドだ。
ただし、使用上の注意があるので、できれば使わないようにしたいメソッドでもある。
今どきjava.io.Fileクラスを積極的に使うこともないと思うが、Java6以下のバージョンをターゲットとした開発プロジェクトの場合、Filesクラスが使えないために他に選択肢がないことがあるのだ。
何が問題なのか
APIをよく見るとちゃんと書いてあるのだが、「メソッドの動作の多くの部分が本質的にプラットフォーム依存」だという点が問題だ。
「ファイルをファイル・システム間で移動できないことがある」とも書かれている。
そもそも安易に使用してはならないメソッドなのだ。
例えばLinuxの場合だと、パーティションをまたいでファイルを移動しようとすると、エラーになってしまう。
運が悪いと、テスト環境では何も問題が起こらなかったのに、いざ商用環境にリリースしたらエラーが発生したなんてことも起こり得る。
原因
File.renameToメソッドは、ファイルの実体を移動しているわけではなく、ファイルのロケーション情報のみを書き換えているらしい。
そのため、そもそもパーティションをまたぐような移動は、プラットフォーム側が気を利かせてサポートでもしてくれない限り不可能なようだ。
対策
Java7以降なら、java.nio.Files.moveメソッドを使うのがよさそうだ。
どうしてもJava6で作らないといけない場合は、他のライブラリーを利用するか、自作するしかなさそうだ。
古いJavaを使っているような現場には、ファイルコピーメソッドくらいは普通に用意されていることが多いので、それを利用するのだ。
僕の場合は、そのような既存ファイルコピーメソッドと、File.deleteメソッドの組み合わせで対応した。
自作する場合
どうしても自作以外の方法が取れない場合もあるだろう。
外部ライブラリーの利用が制限されているようなプロジェクトも、世の中には多々あるものだ。
そのような場合は、Java6時代の既存のコードを参考にするのがよい。
commons-ioのファイルコピーメソッドの抜粋を以下に挙げておく。
現時点での最新ソースなので、うまく真似をすれば動作するだろう。
final byte[] buffer = new byte[bufferSize];
int count = 0;
int n = 0;
while (-1 != (n = input.read(buffer))) {
output.write(buffer, 0, n);
count += n;
}
return count;
bufferSizeに何を指定すればよいのか少し悩むが、Java6が動いているような古い環境では、あまり大きな値を設定しないことをおすすめする。
もっとも、4096程度の値なら問題になることはまずないと思われる。
まとめ
File.renameToメソッドは極力使わないようにする。
Java7以降であれば、Files.moveメソッドで代替する。
Java6以前であれば、他のライブラリーを利用するか自作する。
もし自作するなら、上掲のcommon-ioのソースを参考にしよう。