File.renameToメソッドを使用する際の注意事項

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のソースを参考にしよう。

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です