SeekableByteChannelを利用したファイルのランダムアクセス処理
Java7ではSeekableByteChannelこれはファイルのランダムアクセス処理を行うためのノンブロッキングIOクラスが存在します。
ByteBufferクラスと合わせて利用するのですが、今回はこのクラスを用いた簡単なサンプルをメモとして残すことにします。
当該クラスを用いたランダムアクセス処理に利用するために以下のようなファイルを用意します。
It was a beautiful Sunday morning.
The rain was gone when I woke up. So I opened the window to look out.
I saw a dew on the class and heard the birds sing.
意味が分からない文章がありますが、これは後々その部分を当該クラスを用いて修正するためにあえて意味の通らない単語を利用しています。
SeekableByteChannelはFilesクラスのnewByteChannelメソッドにPathオブジェクトを渡して取得します。
読み込みを行う際はSeekableByteChannelのposition(long)メソッドでファイルのカーソルを指定位置まで移動し、readメソッドでByteBufferに指定バイト数読み込むことが可能です。
書き込み時は、SeekableByteChannel取得時にnewByteChannelの第2引数にStandardOptionOption.APPENDを指定した場合はカーソルがファイルの最終位置に移動し、特定の文字を追記することが可能です。
StandardOpenOption.WRITEを指定した場合はpositionメソッドで指定したバイト位置から、指定文字列で上書きすることが可能です。
では、最初に用意した文章からbeautifulという単語と「when I woke up」というセンテンスを読み込み表示する処理と、最終行のon the classのclassをgrassに変更し、文章の最後に「Clouds were moving fast in the sky.」という1文を追加する処理を以下に示します。
import java.io.BufferedReader; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.SeekableByteChannel; import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; public class SeekableMain { private static final int BUFFER_SIZE = 64; public static void main(String[] args) throws IOException { Path path = Paths.get("path_to_file"); System.out.println("--------------------------------"); readAndDisplay(path); System.out.println("--------------------------------"); writeAndDisplayAll(path); } /* * SeekableByteChannelとByteBufferを用いて任意の位置から指定バイトの文字を読み込み出力する。 */ private static void readAndDisplay(final Path path) throws IOException { try (SeekableByteChannel channel = getSeekableByteChannel(path)) { ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE); // beautifulを出力 display(channel, buffer, 9, 9); buffer.clear(); // 「when I woke up」を出力 display(channel, buffer, 53, 14); } } private static void display(SeekableByteChannel channel, ByteBuffer buffer, int start, int length) throws IOException { channel.position(start); channel.read(buffer); for (int i = 0; i < length; i++) { System.out.print((char)buffer.get(i)); } System.out.println(); } /* * 指定位置に特定の文字列を書き込む。 */ private static void writeAndDisplayAll(final Path path) throws IOException { // 書き込みモードでチャネルオープン try (SeekableByteChannel channel = getSeekableByteChannel(path, StandardOpenOption.WRITE)) { // classをgrassに修正 String modifier = "grass"; channel.position(124); channel.write(ByteBuffer.wrap(modifier.getBytes())); } // 追記モードでチャネルオープン try (SeekableByteChannel channel = getSeekableByteChannel(path, StandardOpenOption.APPEND)) { // 最終行に1文追加 String appended = " Clouds were moving fast in the sky."; channel.write(ByteBuffer.wrap(appended.getBytes())); } // BufferedReaderで全ファイル内容を出力する。 try (BufferedReader reader = Files.newBufferedReader(path, Charset.defaultCharset())) { String line = null; while ((line = reader.readLine()) != null) { System.out.println(line); } } } private static SeekableByteChannel getSeekableByteChannel(Path path, StandardOpenOption... opts) throws IOException { return Files.newByteChannel(path, opts); } }
処理結果は以下のようになるかと思います。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
beautiful
when I woke up
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
It was a beautiful Sunday morning.
The rain was gone when I woke up. So I opened the window to look out.
I saw a dew on the grass and heard the birds sing. Clouds were moving fast in the sky.
簡単ではありますが、以上です。それではよいランダムアクセス生活を。