結論
-
Java7以降で、特別な事情がない場合は java.nio.file.Files#copy(Path, Path, CopyOption) 等、標準ライブラリの機能をご利用ください。
-
Java6以前の場合、可能であれば Apache Commons の、Commons-IOに含まれる__FileUtils#copyFile(File, File)__ 等、定評のあるライブラリの機能をご利用ください。
どうしても独自実装したい場合
2017年現在、独自実装する必要はないはずですが、なんらかの理由により独自実装する場合の話です。Webを検索すると、以下のようなコードが散見されます。
public static void copyFile(File sf, File df) {
FileChannel sc = null, dc = null;
try {
sc = new FileInputStream(sf).getChannel();
dc = new FileOutputStream(df).getChannel();
dc.transferFrom(sc, 0, sc.size());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (dc != null) try { dc.close(); } catch (IOException e) {}
if (sc != null) try { sc.close(); } catch (IOException e) {}
}
}
このメソッド、基本的には動作に問題ないのですが、静的構文解析ツールによっては、
sc = new FileInputStream(sf).getChannel();
このFileChannelをメソッドチェインで取得している箇所で、__「FileInputStreamが閉じられていない可能性がある」__と警告してきます (FileOutputStreamも同様)
幸い、Java6の java.io.FileInputStream#close() のドキュメントには、
ファイル入力ストリームを閉じ、このストリームに関連するシステムリソースを解放します。
このストリームにチャネルが関連付けられている場合は、そのチャネルも閉じます。
とありますので、FileInputStream(FileOutputStream)を閉じましょう。こんな感じでしょうか (FileChannelも閉じても問題ないです。FileInputStreamとFileChannel、両方のcloseメソッドを呼んでも落ちることはありません。意味もありませんが)
public static void copyFile(File sf, File df) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream(sf);
fos = new FileOutputStream(df);
FileChannel sc = fis.getChannel();
FileChannel dc = fos.getChannel();
dc.transferFrom(sc, 0, sc.size());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null) try { fos.close(); } catch (IOException e) {}
if (fis != null) try { fis.close(); } catch (IOException e) {}
}
}
ということで、__サンプル2__の方が、後から静的構文解析ツール等を導入した際、警告される可能性が低くなります。Webを検索して__サンプル1__をコピペするくらいなら、__サンプル2__をご利用ください。後でメンテナンスする人が楽になりますので
なお、Java7以降で独自実装する場合は、try-with-resources文をお使いください。すごくシンプルになります。
参考
- いままでの主なファイルコピー方法と、その実装・処理速度について解説なされています