解答例 - 実習課題3 - 3.ファイルチャネル
(実習課題3)
以下の仕様を満たすアプリケーションを作成してください。
- Long型のデータ1つを保持するファイルをカウンタとして扱うプログラム。ファイル名は固定で構わない。
- ファイルから数値を読み込み、10秒後にその値を+1した値をファイルに書き込んでプログラムを終了すること。書き込んだ値はコンソールにも出力すること。
- カウンタファイルが存在しなかった場合、値0が書き込まれたファイルを新規作成し直ちにプログラムを終了すること。
- Long型データの入出力にはLongBufferを利用すること。
- カウンタの増加を排他的に行うこと。異なる仮想マシン上で同時にこのプログラムが実行されても、プログラムを実行された回数だけ確実にカウンタ値が増加していること。
解答例
public class Main {
private static final String COUNTER_FILE = "counter.dat";
private static final long INIT_START = 1;
public static void main(String[] args) {
FileChannel inCh = null;
File counter = new File(COUNTER_FILE);
if (!counter.exists()) {
try {
counter.createNewFile();
RandomAccessFile out = new RandomAccessFile(counter, "rw");
FileChannel outputChannel = out.getChannel();
MappedByteBuffer buffer = outputChannel.map(FileChannel.MapMode.READ_WRITE,
0,
8);
// 初期値1を書き込んで終了
buffer.putLong(INIT_START);
outputChannel.write(buffer);
outputChannel.force(false);
outputChannel.close();
return;
} catch (IOException err) {
err.printStackTrace();
}
}
// ファイルを読み込む
try {
RandomAccessFile out = new RandomAccessFile(counter, "rw");
inCh = out.getChannel();
counter(inCh);
} catch (IOException e) {
e.printStackTrace();
}
}
private static void counter(FileChannel inCh) throws IOException {
ByteBuffer bufByte = ByteBuffer.allocate(8);
bufByte.position(0);
// ロック
FileLock lock = inCh.tryLock();
inCh.read(bufByte);
bufByte.position(0);
long counter = bufByte.getLong();
bufByte.position(0);
bufByte.putLong(++counter);
bufByte.position(0);
// ロック解除
lock.release();
try {
FileChannel channel = new FileOutputStream(new File(COUNTER_FILE)).getChannel();
channel.write(bufByte);
channel.force(true);
channel.close();
} catch (RuntimeException e) {
System.out.println(e.getMessage());
System.out.println(e.getClass().getName());
}
inCh.close();
}
}

