だいこんの日々2

軸足をtwitterとfacebookに移しつつも、技術的な話はここに書いていきます。

transferFrom/transferToによる2GBを超えるファイルのコピーで嵌められる

久々に書いてみる。

Javaでファイルをコピーするには、java.nioのtransferFrom/transferToを使うと早いとされていますが、そこには落とし穴が。

だいたい、どんなサイトでも以下のようなサンプルが載っています。

FileChannel src = new FileInputStream(source).getChannel();
FileChannel dst = new FileOutputStream(destination).getChannel();
dst.transferFrom(src, 0, src.size());
dst.close();
src.close();

が、これがダメなんだな。
以下のようにしないと、不完全なコピーが出来上がることがある。

FileChannel src = new FileInputStream(source).getChannel();
FileChannel dst = new FileOutputStream(destination).getChannel();
long pos = 0;
long size = src .size();
while (pos < size) {
   long add = src .transferTo(pos, size, dst);
   if (add == 0) {
     throw new IOException();
   }
   pos += add;
}
dst.close();
src.close();

そう、1回でコピーしきれないことがある。それが2G超のファイルで顕著に表れる。
(JVM実装依存だとは思うんだが。)

単純にStreamをwhileで回すだけだと問題は起きないので、高速化しようとして陥る罠ってところですな。