Java ファイルコピー(簡単・高速)
Java ファイルコピー(簡単・高速)FileChannel#transferTo
Java でファイルをコピーするサンプルプログラムを紹介します。
サンプルプログラムは、J2SE1.4 で導入された New I/O の java.nio.channels.FileChannel#transferTo メソッドを利用します。
データの読み込みに必要なバッファを意識すること無く、コピー処理のプログラムを記述でき、最もシンプルなコーディングとなります。
チャネルとは
チャネルという言葉は、様々な意味で使われていますが、
基本的には他のデバイスとのあいだでデータの入出力を行うための伝送路を示すようです。java.nio.channels.FileChannel はファイルへの読み込み、書き込みを行うための接続を表すクラスとなります。
transferTo メソッドは、コピー元となるファイルから、コピー先のチャネルにバイトデータを転送することができます。
以下、JavaAPI ドキュメントから引用。
transferTo(long position, long count, WritableByteChannel target)
このチャネルのファイルから指定された書き込み可能なバイトチャネルへバイトを転送します。
このチャネルからデータを読み込んでターゲットチャネルに書き込むという単純なループよりも、このメソッドのほうがずっと効率的に処理できる可能性があります。多くのオペレーティングシステムは、ファイルシステムキャッシュからターゲットチャネルへバイトを直接転送できます。 このとき、バイトのコピーは行われません。
今回の検証結果では、通常のストリームを利用する方法や、 FileChannel の他の方法( ByteBuffer#allocateDirect メソッドを使用する方法等)より高速にコピー処理が行えました。
サンプルプログラム
実行
サンプルプログラムのファイルコピーを行うために、Cドライブ直下に 100MB のファイル「100M.txt」を用意しました。
サンプルプログラムでは C:\100M.txt をコピーして C:\a.txt のファイルを作成します。
尚、サンプルの実行は以下の環境で行いました。
OS : WindowsXP
CPU : Athlon 1.46GHz
メモリー : 1GB
JRE : 1.6.4
/** * 実行例 * @param args */ public static void main(String[] args) { try { copyTransfer("C:\\100M.txt", "C:\\a.txt"); } catch (IOException e) { e.printStackTrace(); } }◆実行結果
FileChannel#transferTo メソッドを利用したコピー処理では
100MB のファイルのコピー処理が 3 秒程度で完了しました。またコピー処理中のヒープ使用量についても 300 (KB) 程でした。
ちなみに、Java ファイルコピー(バッファサイズを変更)で紹介している方法では、
最も効率の良かった 1000KB のバッファサイズを指定した場合で、処理時間は 4 秒程度、ヒープ使用量は 1,300KB 程度でした。
ストリームによるファイルコピーでも、バッファサイズをチューニングする事で高速化されるため、
一つのファイルをコピーする処理ではそれ程差は無いと言えるでしょう。
しかしながら、大きなファイルを連続してコピーする場合や、複数のコピー処理を平行して実行する場合では、処理速度・ヒープ使用量の観点で FileChannel は効果を発揮できるでしょう。
Chat&Messenger でのファイル転送機能では
Chat&Messenger でのファイル転送機能では、Java ファイルコピー(バッファサイズを変更)で紹介しているストリームを利用したコピーを行っています。
理由は、ソフトを不特定多数の環境へ配布するため、少しでも実績があり枯れた機能を利用した方が、開発当時は安心だったためです。ただ、将来的にはチャネルを利用した方法に切り替えるよう検討しています。