Rainbow Engine

IT技術を分かりやすく簡潔にまとめることによる学習の効率化、また日常の気付きを記録に残すことを目指します。

Java

InputStreamやInputStreamReaderやBufferedReaderの機能や役割の違い+速度測定で比較をした結果共有

投稿日:2020年7月20日 更新日:

(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) 概要

Stream系のクラス(InputStream、OutputStreamなど)はバイトの読み書きを行うために利用されます。StreamReader/系のクラス(InputStreamReader、OutputStreamWriter)は文字列の読み書きも扱えて、多くのエンコード/デコードメソッドもサポートしています。
更にBufferedReaderは上記に加え、性能向上のためデータをバッファと呼ばれるメモリ上の領域に蓄えて、ディスクI/Oやネットワークアクセス回数を削減しています。
InputStreamにも種類があり、それぞれ異なるデータソースに対してアクセスします。例えばFileInputStreamはファイル(txt等)を対象とし、ファイルからバイトを読み取ります。

(表)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のread()メソッドで次の「1バイト」を読み込みます。
・これを(char)等でキャストしてあげる事でバイトを文字に変換する事ができます(1文字取り出せる)。
・この仕組みはデータがファイルから提供される時やネットワーク越しに受領する時に効果を発揮します。

(例)
InputStream InStream = new FileInputStream("c:\\temp\\sample.txt");

(図222)
例えば「HelloWorld」という文字列のバイトデータがあった場合、InputStreamのread()メソッドではそれを1バイトずつ読み込みます。下図の例では初回のread()では1バイト目である「72」が読み込まれます。

目次にもどる

(2-3) InputStreamReader

データの読み書きを行うためのクラスで、InputStreamReaderはInputStremをラップしたクラスです。InputStreamでは次の「1バイト」を読み込むのに対して、InputStreamReaderでは文字を「1文字」ずつ読む事ができます。それにより、バイトストリームから文字ストリームへの橋渡しを行います。
ASCII文字など1バイトしか使用しない文字の場合、InputStreamとの違いを実感しにくいですが、漢字などのマルチバイト文字を読み込む際に明確な違いがあります。また、コンストラクタにて文字コードを指定する事で、バイトを読込んで指定されたcharsetを使用して文字にデコードする事も出来ます。

(図223)
例えば「HelloWorld」という文字列のバイトデータがあった場合、InputStreamReaderのread()メソッドではそれを1文字ずつ読み込みます。下図の例では初回のread()では1文字目である「H」のバイト値「72」が読み込まれて、「H」が取得されます(厳密にはchar型にキャストする)。

目次にもどる

(2-4) BufferedReader

BufferedReaderは「InputStreamReader」と「FileReader」をラップしたクラスです。ラップをする事で、バッファリングにより変換効率を上げる事ができます。以下はInputStreamReaderをラップした例です。
 
(例)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

目次にもどる

Adsense審査用広告コード


Adsense審査用広告コード


-Java

執筆者:


comment

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

関連記事

Spring Bootでpom.xmlに「Unknown error」が出た時の対処方法について

  <目次> (1) Spring Bootでpom.xmlに「Unknown error」が出た時の対処方法について  (1-1) 発生状況  (1-2) 原因  (1-3) 対処法①(非 …

WindowsのcmdからJavaファイルを作成・コンパイル・実行する方法

“Windows”の「コマンドプロンプト」からJavaファイルを作成・コンパイル・実行する方法について記述します。今回の操作は全てコマンドラインインターフェイスから実施いたしま …

JSP/Servletでcsvをダウンロードする機能を作成する手順

<目次> (1) JSP/Servletでcsvをダウンロードする機能を作成する手順  (1-0) 実現方針  (1-1) STEP1:Servletの追記  (1-2) STEP2:JSPの追記   …

Javaのprintfで右揃え(右詰め)や左揃え(左詰め)にフォーマットする方法

<目次> (1) Javaのprintfで右揃えや左揃えにフォーマットする方法  (1-1) 構文  (1-2) 右揃えの方法  (1-3) 左揃えの方法  (1-4) 主要な変換文字(s,d,f,t …

int型のオーバーフロー(桁あふれ)とは?実際の発生パターンと併せてご紹介

  <目次> (1) int型のオーバーフロー(桁あふれ)とは?実際の発生パターンと併せてご紹介  (1-1) int型のオーバーフローとは?  (1-2) int型のオーバーフローが発生す …

  • English (United States)
  • 日本語
Top