特集PC技術

Java言語入門 ~C言語を学んだ君へ~

 

[第16回]入出力

Javaでの入出力を行うための基礎を説明します。

目次

[1] 入出力の基礎知識

Javaで入出力を行うにはストリームを使います。
ストリームとは「データの流れ」を表す抽象的な概念です。
ストリームを使用する目的は、異なる物理デバイスでも、簡単に入出力を行うためです。

入出力と言ってもいくつもの種類があります。
例えば、キーボード入力とモニタ出力、ファイルへの入出力などです。
これらに対して、個別に入出力の方法を適用することはとても大変です。
しかし、ストリームという抽象的な概念を使うことで、同じ処理で入出力が可能になります。

文字ストリームとバイトストリーム

ストリームには2つの種類があります。
それは文字ストリームバイトストリームです。

文字ストリームとは、テキストデータを扱うためのストリームです。
バイトストリームとは、バイナリデータを扱うためのストリームです。

例えば、メモ帳などで作成する文章は、テキストデータであり、
画像、音楽ファイルはバイナリデータになります。

対象となるデータによって、2つのストリームを使い分けて入出力を行います。

入出力パッケージ

Javaには入出力を行うためのクラスがパッケージとして用意してあります。
そのパッケージが「java.io」です。
このパッケージには次のクラス関係があります。

入出力クラス

それぞれのストリームに対してのクラスが提供されています。
少し多いですが、この回で使用するクラスは

「InputStreamクラス」
「BufferedReaderクラス」
「BufferedWriterクラス」
「FileReaderクラス」
「FileWriterクラス」

の5つです。なお、上記以外にも入出力クラスはあります。
他のクラスについての説明はAPIを見てください。

[2] コンソール入力

コンソールからの入力方法を説明します。
C言語を学んだ方によっては、少し遅いと思ったことでしょう。
しかし、Javaでは入出力を行うために、「クラス」、「パッケージ」、「例外」など、
多くの知識が必要になります。少し難しいかもしれません。

良くない方法

いきなり「良くない方法」を説明します。良い方法はあとで説明します。

ところで、コンソール出力をする場合は、「System.out.println()」を使います。
この「out」とは、PrintStreamクラスであり、このクラスのメソッドを用いて出力を行います。
この他に、Systemクラスには「in」というオブジェクトを持っています。
これはInputStreamクラスであり、標準でキーボード入力ができます。
つまり、このクラスを使うことで、コンソール入力が行えます。

では、コンソール入力のサンプルプログラムを次に示します。
なお、読み込みにはInputStreamクラスのreadメソッドを使います。

サンプルプログラム1
import java.io.*;	// インポート

public class Java16_01 {
	public static void main(String args[]) {
		try {
			System.out.print("入力してください:");
			int n = System.in.read();
			System.out.println("入力したデータ:" + n);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
実行結果1

悪い入出力

実行結果より「何か」の入力はできたと思います。
ただし、正しい文字入力はできていません。
その理由は、InputStreamクラスは1バイトデータしか扱えないからです。
つまり、文字入力はできません。
これを改善するには「ストリームのラッピング」が必要になります。

ストリームのラッピング

ストリームのラッピングとは、ストリームをストリームで覆い(ラッピングを行い)、高性能な入出力ストリームにすることです。

上のプログラムではInputStreamクラスを使ってコンソール入力を行いました。
しかし、このクラスは「低機能」のため、文字入力が正しくできませんでした。
そこで、ラッピングを行って「高性能」にします。

方法はInputStreamクラスをInputStreamReaderクラスでラッピングします。
これによって、文字単位の入力ができるようになります。

さらに、InputStreamReaderクラスをBufferedReaderクラスでラッピングすると、
一行単位の入力ができるようになります。それにはreadLineメソッドを使います。
次のサンプルプログラム2を見てください。

サンプルプログラム2
import java.io.*;

public class Java16_02 {
	public static void main(String args[]) {
		try {
			// InputStream→InputStreamReader→BufferedReaderの順にラッピング
			BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
			System.out.print("入力してください:");
			String s = br.readLine();
			System.out.println("入力したデータ:" + s);
			br.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
実行結果2

正しい入出力

今度は正しくコンソール入力ができます。
少し、ラッピングの方法は難しかったかもしれません。
なお、作成したストリームを使用した後は、close()メソッドで終了してください。
これについては、C言語と同じです。

ところで、このサンプルプログラム2ではBufferedReaderクラスを使いました。
しかし、このクラスを使わなくても、InputStreamReaderクラスのみで文字入力は可能です。
使用した理由は、BufferedReaderクラスを使うことで、文字入力の効率が向上するからです。
そのため、文字列を扱うときは、BufferedReaderを使用した方法が良いでしょう。

[3] ファイル入出力

ファイル入出力について説明します。
ここでは、ファイル入出力の例として、ファイルのコピーを行います。

前準備(ファイルの作成)

まず、ファイル入出力に使うファイルを作成します。

ファイルは入力用と出力用の2種類を作成してください。
そして、ファイル名は「input.txt」と「output.txt」とします。
Eclipseの場合、「ファイル」→「新規」→「ファイル」をクリックします。
そして、プロジェクトを指定し、ファイル名を書きます。
その後、「終了」をクリックすると、ファイルが作成できます。

作成できたら、「input.txt」ファイルに次のように書いてください。

ほぷしぃ
ABCDEFG
12345

以上でファイル作成は終了です。

ファイル入出力の手順

ファイル入出力には

FileReaderクラス
BufferedReaderクラス
FileWriterクラス
BufferedWriterクラス

の4つを使います。
では、ファイル入出力の例として、ファイルをコピーする処理を行います。
input.txtに書いてある内容が、output.txtにコピーされるようにします。

入出力の手順は次の通りです。

1.ファイル入出力ストリームの作成
2.入力ファイルから1行読み込む
3.出力ファイルに、読み込んだ1行を書き込む
4.ファイルの最後まで読み書きの繰り返し
5.ファイル入出力ストリームを閉じる

基本的な流れを書きました。
では、次にサンプルプログラムを示します。

サンプルプログラム

サンプルプログラムです。
注意点として、上記で作成したファイルと同じプロジェクトに置いてください。

import java.io.*;

class Java16_03 {
	public static void main(String args[]) {
		try {
			// ①ファイル入出力ストリームの作成
			BufferedReader br = new BufferedReader(new FileReader("input.txt"));
			BufferedWriter bw = new BufferedWriter(new FileWriter("output.txt"));

			String str;
			while (true) {
				// ②入力ファイルから1行読み込む
				str = br.readLine();
				if (str == null) break;
				// ③出力ファイルに、読み込んだ1行を書き込む
				bw.write(str + "\n");
			} // ④ファイルの最後まで読み書きの繰り返し
			
			// ⑤ファイル入出力ストリームを閉じる
			br.close();
			bw.close();
			
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
実行結果(output.txtファイル)

ファイルコピー

output.txtにinput.txtの内容がコピーされたことが確認できます。
少しプログラムの解説をします。

ファイルへの読み込みは一行単位です。
そのため、ループを使って繰り返し行います。
そして、ファイルの最後まで読み込むと、readLineメソッドの戻り値がnullになります。
そのとき、ループを抜けるように処理しています。
また、writeメソッドでは文字列を書き込んでいます。
このとき、"\n"を追加しています。
使用しないと、改行できません。

[4] データ解析

入出力の方法はだいたいわかったと思います。
次は、データの型を意識して読み込みを行います。

StringTokenizer

これまでの入力は文字列(String型)のみでした。
しかし、入力データは文字列ばかりでなく、数値もあります
また、文字列と数値の混合データも考えられます。
こうした場合に、StringTokenizerクラスを使います。
このクラスは、入力データを解析し、トークンを生成することができます。
トークンとは、文字列・数値などの最小単位のことです。

例えば、次のようなファイルデータがあります。

太郎,日本,10
次郎,中国,11
三郎,独逸,12

見方は一行に「名前」と「国籍」と「年齢」が書いてあります。
つまり、3人分の個人情報です。

このデータを読み込む場合、これまでの方法では"太郎,日本,10"という単なる文字列で読み込んでしまいます。
このままでは、正しい入力とは言えません。

しかし、StringTokenizerクラスを使うと、"太郎"と"日本"と"10"という3つのトークンに分けることができます。
ただし、「型」はすべてString型です。
そのため、Integerクラスを使って、年齢は数値に変換します。
これで正しいデータ入力になります。
では、次にデータ解析のサンプルプログラムを示します。

サンプルプログラム

入力ファイル「text.txt」には

太郎,日本,10
次郎,中国,11
三郎,独逸,12

の個人情報を入れてください。

import java.io.*;
import java.util.StringTokenizer;

class Java16_04 {
	public static void main(String args[]) {
		try {
			BufferedReader br = new BufferedReader(new FileReader("text.txt"));

			String str;
			String name;
			String nationality;
			int age;
			while (true) {
				str = br.readLine();
				if (str == null) break;
				// 区切り文字","を指定する
				StringTokenizer st = new StringTokenizer(str, ",");
				// トークンを取り出す
				name = st.nextToken();
				nationality = st.nextToken();
				age = Integer.parseInt(st.nextToken());
				// 出力
				System.out.print("名前は" + name);
				System.out.print(" 国籍は" + nationality);
				System.out.println(" 年齢は" + age);
			}
			br.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
実行結果

トークンとファイル

ファイル入力の方法は今までと同じです。
入力した文字列を使って、StringTokenizerクラスでトークンに切り分けます。
このとき、どこで区切るかはコンストラクタで指定します。
トークンはnextTokenメソッドで受け取ります。
ただし、文字列しか返さないので、年齢などの異なる型には、ラッパークラスを用いて変換するようにしてください。
なお、StringTokenizerクラスは「java.util」パッケージにあるので、必ず、importするようにしてください。

[5] 練習問題 第1問

ファイルへの書き込みの練習です。
ファイル「test.txt」に「1,2,3,4,5,6,7,8,9,10」を書き込むプログラムを作成してください。
ファイル「test.txt」は以下のように表示されます。

出力結果

[6] 第1問解答

[7] 練習問題 第2問

練習問題1でファイル「test.txt」に書き込んだ文字列「1,2,3,4,5,6,7,8,9,10」を読み込み、','でトークンに分け、数値に変換します。
そして、奇数、偶数別に合計を計算し、コンソールに表示してみましょう。
コンソールには以下のように表示されます。

16練習問題2実行結果

注意事項

なお、文字列をトークンに分けるには、StringTokenizerクラスを使いましょう。
このクラスには、以下の主要メソッドがあります。必要なら使いましょう。

・ public boolean hasMoreTokens()・・・トークンがまだある場合trueを返します
・ public String nextToken()・・・次のトークンを返します

[8] 第2問解答

コメントの投稿


画像の中に見える文字を入力してください。

トラックバックURL

http://www.isl.ne.jp/cgi-bin/mt/mt-tb.cgi/1083

pagetopこのページの先頭へ戻る