ストリームによるファイルコピー
シンプルなストリームによるファイルコピー
public static void copy(String src, String dest) throws IOException { InputStream in = null; OutputStream out = null; try { in = new BufferedInputStream(new FileInputStream(src)); out = new BufferedOutputStream(new FileOutputStream(dest)); byte[] buf = new byte[BUFFER_SIZE]; int length; while (-1 < (length = in.read(buf))) { out.write(buf, 0, length); out.flush(); } } finally { closeIgnoringException(in); closeIgnoringException(out); } }
BUFFER_SIZE は 4096 とかプラットフォームに応じた値にする。
closeIgnoringException はヘルパーメソッドです。
private static void closeIgnoringException(Closeable closeable) { if (closeable != null) { try { closeable.close(); } catch (IOException e) { // do nothing } } }
ダイレクト・バッファー
ヒープ外にメモリが確保され、バッファー操作に高速なネイティブI/O操作が直接使用されます。ただしアロケートのコストが大きいため、長期的なバッファーへの使用が効果的です。
public static void directBufferCopy(String src, String dest) throws IOException { FileChannel srcChannel = null; FileChannel destChannel = null; try { srcChannel = new FileInputStream(src).getChannel(); destChannel = new FileOutputStream(dest).getChannel(); ByteBuffer buffer = ByteBuffer.allocateDirect(BUFFER_SIZE); while (srcChannel.read(buffer) > 0) { buffer.flip(); destChannel.write(buffer); buffer.clear(); } } finally { closeIgnoringException(srcChannel); closeIgnoringException(destChannel); } }
トランスファ
チャネルからチャネルにバイトを転送します。
public static void transferCopy(String src, String dest) throws IOException { FileChannel srcChannel = null; FileChannel destChannel = null; try { srcChannel = new FileInputStream(src).getChannel(); destChannel = new FileOutputStream(dest).getChannel(); srcChannel.transferTo(0, srcChannel.size(), destChannel); } finally { closeIgnoringException(srcChannel); closeIgnoringException(destChannel); } }
メモリー・マップ・ファイル
MappedByteBuffer を使ったファイルコピーの例です。MappedByteBuffer はファイルの一定の領域を直接メモリーにマップします。
public static void mappedCopy(String src, String dest) throws IOException { FileChannel srcChannel = null; FileChannel destChannel = null; try { srcChannel = new FileInputStream(src).getChannel(); destChannel = new FileOutputStream(dest).getChannel(); ByteBuffer srcBuffer = srcChannel.map(FileChannel.MapMode.READ_ONLY, 0, srcChannel.size()); destChannel.write(srcBuffer); } finally { closeIgnoringException(srcChannel); closeIgnoringException(destChannel); } }
srcChannel.map()によるMappedByteBufferの作成は、srcChannel.size()によりサイズ指定をしてますが、大きくなる場合はファイルの一部分をマップして、分割して処理します。
ちなみに・・
ちなみに、ストリームを1つだけ使用する場合は、以下のように宣言と初期化を同時に行うことができます。前述までのように、2つのストリームを使う場合には2つ目の初期化が失敗した場合に、最初のストリームについてクローズ処理を行う必要があるため、初期化はtryブロック中に入れる必要があります。
InputStream in = new BufferedInputStream(new FileInputStream(src)); try { byte[] buf = new byte[BUFFER_SIZE]; int length; while (-1 < (length = in.read(buf))) { ・・・ } } finally { closeIgnoringException(in); }