(0)目次&概説
(1) 記事の目的
(1-1) 目的
(1-2) 前提条件
(2) InputStreamやBufferedReaderとは?
(2-1) 概要
(2-2) InputStream
(2-3) InputStreamReader
(2-4) BufferedReader
(3) InputStreamReaderやBufferedReaderの速度比較
(3-1) 検証概要/条件
(3-1-1) 検証概要
(3-1-2) 検証条件
(3-2) 検証結果/考察
(1) 記事の目的
(1-1) 目的
Javaでデータを読み込みするためのInputStreamクラスやInputStreamReaderやBufferReaderなどの違いや役割について知り、また読み込みの速度面での差についても理解します。
(2) InputStreamやBufferedReaderとは?
(2-1) 概要
(表)Input・Read系クラスの入出力概要
[パッケージ名].[クラス名] | 入力(IN)データ形式 | 出力(OUT)データ形式 | 備考 |
java.lang.Object ∟java.io.InputStream |
バイト | バイト | 引数無しのread()メソッドでは1バイトずつしか読めないため、漢字等のマルチバイト文字が読めない |
java.lang.Object ∟java.io.Reader ∟java.io.InputStreamReader |
バイト | 文字 | 引数無しのread()メソッドでも漢字等のマルチバイト文字が問題なく読める(Reader機能) |
java.lang.Object ∟java.io.Reader ∟java.io.BufferedReader |
文字列? (バッファに蓄えられた文字列?) |
文字列 | マルチバイト文字が問題なく読める上に、バッファ機能により高速化されている |
(2-2) InputStream
InputStream InStream = new FileInputStream("c:\\temp\\sample.txt");
(図222)
例えば「HelloWorld」という文字列のバイトデータがあった場合、InputStreamのread()メソッドではそれを1バイトずつ読み込みます。下図の例では初回のread()では1バイト目である「72」が読み込まれます。
(2-3) InputStreamReader
(図223)
例えば「HelloWorld」という文字列のバイトデータがあった場合、InputStreamReaderのread()メソッドではそれを1文字ずつ読み込みます。下図の例では初回のread()では1文字目である「H」のバイト値「72」が読み込まれて、「H」が取得されます(厳密にはchar型にキャストする)。
(2-4) BufferedReader
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
効率が向上する理由は、バッファと呼ばれる領域に読み込んだデータを保持し(buffering)、そこから読み込みを行う事で都度ディスクI/Oが発生するのを防ぐ事が出来るためです。読込みはreadLine()メソッド等で読込みが行えますが、実際のプログラムのサンプルは3章の速度検証にて紹介します。
(図241)
例えば「HelloWorld」という文字列のバイトデータがあった場合、BufferReaderのreadLine()メソッドではそれを1行ずつ読み込みます。下図の例では初回のread()では1行目である「HelloWorld」のバイト値が読み込まれて、「HelloWorld」が取得されます。
(3) InputStreamReaderやBufferedReaderの速度比較
(3-1) 検証概要/条件
(3-1-1) 検証概要
2章でInputStream、InputStreamReader、BufferedReaderの機能の違いについて見ました。各クラスにはそれぞれread()メソッドがあってデータを読み込めるものの、機能・性能的には異なっており、以下のような優劣関係になる想定です。
InputStream < InputStreamReader = BufferReader
今回の検証ではGitHubのWebAPIを用いて、上記の3種類のクラスのread()メソッドの時間計測を行い、仮説が正しいかどうかを確認します。
(3-1-2) 検証条件
<検証環境>
OS | ディストリビューション | CentOS release 6.10 (Final) |
CPU | モデル | Intel(R) Xeon(R) Gold 6212U CPU @ 2.40GHz |
コア数 | 1 | |
論理プロセッサ数 | 2 | |
Memory | メモリ | 2GB |
Java | バージョン | java version “1.8.0_231” |
<検証条件>
・InputStream、InputStreamReader、BufferedReaderの3つのインスタンスのread()メソッドでの読み込み速度の比較を行います。
・読み込み対象のデータはGitHubのユーザー情報を取得するWebAPIを用いて、1247バイトのデータを読み込む(ほぼ全ての文字がASCII文字のため、ほぼ1247文字)
・計測区間の1つ目は「インスタンスの作成」で、これは初回作成時にヒープ領域に格納されて2回目以降は早くなる事が想定されるが、念のため10回計測。
・計測区間の2つ目は「インスタンスの作成」でread()メソッドを用いて読み込みに要した時間を計測します。こちらも10回ずつ計測を行います。
(図312)
(3-2) 検証結果/考察
・約1250バイトを読む場合、BufferReaderクラスは他2つと比較して平均約3ms速かった。
・InputStreamReader自体はInputStreamと比べてほぼ同等速度だが、速度以外の面でマルチバイト文字(漢字など)が正しく読めている点でInputStreamよりも処理機能が向上している。
・今回の小規模な読み込みにおいては、読み込みの速度よりもInputStreamのインスタンス生成の時間の方が約100倍の時間(平均0.48秒)を要している。
①BufferReader
区分 | Start | End | Time |
インスタンス作成:1回目 | 16:22:54.709 | 16:22:54.709 | 0:00:00.000 |
インスタンス作成:2回目 | 16:23:51.049 | 16:23:51.050 | 0:00:00.001 |
インスタンス作成:3回目 | 16:23:57.271 | 16:23:57.271 | 0:00:00.000 |
インスタンス作成:4回目 | 16:24:07.367 | 16:24:07.368 | 0:00:00.001 |
インスタンス作成:5回目 | 16:24:19.200 | 16:24:19.201 | 0:00:00.001 |
インスタンス作成:6回目 | 16:24:27.206 | 16:24:27.206 | 0:00:00.000 |
インスタンス作成:7回目 | 16:24:34.954 | 16:24:34.955 | 0:00:00.001 |
インスタンス作成:8回目 | 16:24:42.062 | 16:24:42.063 | 0:00:00.001 |
インスタンス作成:9回目 | 16:24:52.708 | 16:24:52.709 | 0:00:00.001 |
インスタンス作成:10回目 | 16:24:59.656 | 16:24:59.657 | 0:00:00.001 |
平均 | – | – | 0:00:00.001 |
区分 | Start | End | Time |
read():1回目 | 16:22:54.709 | 16:22:54.711 | 0:00:00.002 |
read():2回目 | 16:23:51.050 | 16:23:51.051 | 0:00:00.001 |
read():3回目 | 16:23:57.271 | 16:23:57.273 | 0:00:00.002 |
read():4回目 | 16:24:07.368 | 16:24:07.369 | 0:00:00.001 |
read():5回目 | 16:24:19.201 | 16:24:19.202 | 0:00:00.001 |
read():6回目 | 16:24:27.206 | 16:24:27.208 | 0:00:00.002 |
read():7回目 | 16:24:34.955 | 16:24:34.957 | 0:00:00.002 |
read():8回目 | 16:24:42.063 | 16:24:42.064 | 0:00:00.001 |
read():9回目 | 16:24:52.709 | 16:24:52.710 | 0:00:00.001 |
read():10回目 | 16:24:59.657 | 16:24:59.659 | 0:00:00.002 |
平均 | – | – | 0:00:00.002 |
②InputStreamReader
区分 | Start | End | Time |
インスタンス作成:1回目 | 16:48:41.067 | 16:48:41.068 | 0:00:00.001 |
インスタンス作成:2回目 | 16:50:10.680 | 16:50:10.680 | 0:00:00.000 |
インスタンス作成:3回目 | 16:51:02.717 | 16:51:02.719 | 0:00:00.002 |
インスタンス作成:4回目 | 16:53:49.629 | 16:53:49.630 | 0:00:00.001 |
インスタンス作成:5回目 | 16:56:40.031 | 16:56:40.032 | 0:00:00.001 |
インスタンス作成:6回目 | 16:57:28.538 | 16:57:28.538 | 0:00:00.000 |
インスタンス作成:7回目 | 16:59:39.880 | 16:59:39.881 | 0:00:00.001 |
インスタンス作成:8回目 | 17:00:25.076 | 17:00:25.076 | 0:00:00.000 |
インスタンス作成:9回目 | 17:01:10.176 | 17:01:10.176 | 0:00:00.000 |
インスタンス作成:10回目 | 17:02:00.725 | 17:02:00.726 | 0:00:00.001 |
平均 | – | – | 0:00:00.001 |
区分 | Start | End | Time |
read():1回目 | 16:48:41.068 | 16:48:41.071 | 0:00:00.003 |
read():2回目 | 16:50:10.680 | 16:50:10.684 | 0:00:00.004 |
read():3回目 | 16:51:02.719 | 16:51:02.723 | 0:00:00.004 |
read():4回目 | 16:53:49.630 | 16:53:49.637 | 0:00:00.007 |
read():5回目 | 16:56:40.032 | 16:56:40.036 | 0:00:00.004 |
read():6回目 | 16:57:28.538 | 16:57:28.545 | 0:00:00.007 |
read():7回目 | 16:59:39.881 | 16:59:39.885 | 0:00:00.004 |
read():8回目 | 17:00:25.076 | 17:00:25.083 | 0:00:00.007 |
read():9回目 | 17:01:10.176 | 17:01:10.183 | 0:00:00.007 |
read():10回目 | 17:02:00.726 | 17:02:00.730 | 0:00:00.004 |
平均 | – | – | 0:00:00.005 |
③InputReader
区分 | Start | End | Time |
インスタンス作成:1回目 | 17:03:52.552 | 17:03:53.025 | 0:00:00.473 |
インスタンス作成:2回目 | 17:05:05.095 | 17:05:05.567 | 0:00:00.472 |
インスタンス作成:3回目 | 17:05:47.131 | 17:05:47.605 | 0:00:00.474 |
インスタンス作成:4回目 | 17:06:43.486 | 17:06:43.994 | 0:00:00.508 |
インスタンス作成:5回目 | 17:15:01.895 | 17:15:02.390 | 0:00:00.495 |
インスタンス作成:6回目 | 17:16:16.844 | 17:16:17.319 | 0:00:00.475 |
インスタンス作成:7回目 | 17:17:25.534 | 17:17:26.039 | 0:00:00.505 |
インスタンス作成:8回目 | 17:18:21.184 | 17:18:21.708 | 0:00:00.524 |
インスタンス作成:9回目 | 17:19:19.913 | 17:19:20.400 | 0:00:00.487 |
インスタンス作成:10回目 | 17:20:29.653 | 17:20:30.121 | 0:00:00.468 |
平均 | – | – | 0:00:00.488 |
区分 | Start | End | Time |
read():1回目 | 17:03:53.025 | 17:03:53.029 | 0:00:00.004 |
read():2回目 | 17:05:05.567 | 17:05:05.571 | 0:00:00.004 |
read():3回目 | 17:05:47.605 | 17:05:47.608 | 0:00:00.003 |
read():4回目 | 17:06:43.994 | 17:06:43.999 | 0:00:00.005 |
read():5回目 | 17:15:02.390 | 17:15:02.394 | 0:00:00.004 |
read():6回目 | 17:16:17.319 | 17:16:17.324 | 0:00:00.005 |
read():7回目 | 17:17:26.039 | 17:17:26.042 | 0:00:00.003 |
read():8回目 | 17:18:21.708 | 17:18:21.711 | 0:00:00.003 |
read():9回目 | 17:19:20.400 | 17:19:20.404 | 0:00:00.004 |
read():10回目 | 17:20:30.121 | 17:20:30.124 | 0:00:00.003 |
平均 | – | – | 0:00:00.004 |