初出 JAVA PRESS Vol.29

Java API ダイジェスト

java.nio.channels.FileChannel

ファイルに対応するチャネルで、読み込み・書き込みの両方を行うことができます。

FileChannelクラスはチャネルの基本的な機能以外に、次のような特徴があります。

FileChannelオブジェクトを取得するには、FileInputStream, FileOutputStream, RandomAccessFileクラスのgetChannelメソッドを使用します。


ファイルに対応したチャネル

FileChannelクラスの基本機能はByteChannelインタフェースなどで定義されています。ここでは、その他の機能について紹介します。

ファイルをメモリにマップするにはmapメソッドを使用します。

ファイルのメモリへのマップ

FileChannelクラスはチャネルの連結が可能です。transferToメソッドはFileChannelオブジェクトの出力を他のチャネルにつなげます。transferFromメソッドは他のチャネルの出力をFileChannelオブジェクトに結びつけます。

チャネルの連結

ファイルをロックするにはlockメソッドを使用します。

ファイルのロック

多機能なファイルチャネル

ファイルのメモリへのマップ

public MappedByteBuffer map(FileChannel.MapMode mode, long position, long size) throws IOException

ファイルをメモリに直接マップさせます。マップしたファイルへの読み書きは、戻り値のバッファを使用します。バッファへのアクセスはファイルへのアクセスに比べて高速に行えますが、マップしたバッファへの読み書きはオーバヘッドが生じます。

メソッドの第1引数はマップのモードです。モードは3種類で、FileChannel.MapModeクラスで定義されています。

PRIVATEは読み書きできますが、書き込んだ結果はファイルに反映されません(copy-on-write)。

第2引数はファイルをファイルをマップする先頭の位置、第3引数はマップするバイト数を示しています。戻り値はマップされたバッファです。

リスト1はファイルのコピーを行う例です(例外処理は省略してあります)。ここではコピー元をマップしています。

リスト 1 mapメソッドの使用例 (コピー元をマップ)

    FileChannel srcChannel = new RandomAccessFile(srcFile, "r").getChannel();
    FileChannel destChannel = new RandomAccessFile(destFile, "rw").getChannel();
    
    // コピー元ファイルをメモリにマップ
    ByteBuffer buffer = srcChannel.map(FileChannel.MapMode.READ_ONLY, 0, srcChannel.size());
    destChannel.write(buffer);
 
    srcChannel.close();
    destChannel.close();

チャネルの連結

public long transferTo(long position, long count, WritableByteChannel target) throws IOException

public long transferFrom(ReadableByteChannel src, long position, long count) throws IOException

チャネルの連結を行うにはtransferToメソッド、transferFromメソッドを使用します。

FileChannelオブジェクトの出力を、他のWritableByteChannelオブジェクトの入力にするのがtransferToメソッドです。一方のtransferFromメソッドは他のReadableByteChannelオブジェクトの出力をFileChannelオブジェクトの入力に連結します。

引数のpositionはファイルの転送を開始する位置、sizeは転送するバイト数になります。

リスト2は、transferToメソッドを使用したファイルのコピーです。

リスト 2 transferToメソッドの使用例

    FileChannel srcChannel = new FileInputStream(srcFilename).getChannel();
    FileChannel destChannel = new FileOutputStream(destFilename).getChannel();
    
    srcChannel.transferTo(0, (int)srcChannel.size(), destChannel); // チャネルの連結
 
    srcChannel.close();
    destChannel.close();

ファイルのロック

public FileLock lock() throws IOException
public FileLock lock(long position, long size, boolean shared) throws IOException

ファイルを使用している時、他のアプリケーションがそのファイルを使用できなくしたり、リードオンリーでしかオープンできなくするのがロックです。前者を排他ロック、後者を共有ロックといいます。

引数のないlockメソッドはファイル全体を排他ロックします。

引数を使用する場合は第1引数がロックの開始位置、第2引数がロックするバイト数、第3引数がロックの種類の指定です。trueが共有ロック、falseが排他ロックです。

排他ロックではチャネルが書き込み可能、また共有ロックでは読み込み可能でなければなりません。

戻り値はFileLockオブジェクトです。ロックを解放するにはFileLock#releaseメソッドを使用します。

リスト3、4にlockの使用法を示します。リスト3が排他ロックの例、リスト4が共有ロックの例です。

リスト 3 lockメソッドの使用例 (排他ロック)

    FileChannel channel = new FileOutputStream(filename).getChannel();
 
    // ロックをかける。書き込むバイト数が未知なので、sizeは多めにする
    // FileLock lock = channel.lock(); でも OK
    FileLock lock = channel.lock(0, Long.MAX_VALUE, false);
    
    // 出力処理
 
    channel.close();
    lock.release(); // ロックの解放

 

リスト 4 lockメソッドの使用例 (共有ロック)

    FileChannel channel = new FileInputStream(filename).getChannel();
     FileLock lock = channel.lock(0, channel.size(), true); // ロックをかける
    
    // 入力処理
 
    channel.close();
    lock.release(); // ロックの解放

(2003.03)