プロ2 > 資料 > 第8章
第8回:ストリーム入出力と日本語の扱い
目標
- ストリーム入出力の理解
- 日本語の扱いの理解
- コンテナクラスTreeMapの理解
- 正規表現の理解
8.1 ストリーム入出力
- テキスト入出力をストリームとして扱う.キーボード入力,画面出力,ファイルの読み書き,ネットワーク接続などを同じように扱うことができ,機器独立性(device independence)が実現できる.
- 標準の入出力ストリーム
- System.in: 標準入力(キーボード)
- System.out: 標準出力(画面)
- System.err: 標準エラー出力(画面)
- printf()メソッドを使うと,C言語のような書式文字列の出力が可能になる.
- nextLine()とnext()の違い
- nextLine():改行までを読み込み,改行文字は除いてその手前までを1つの文字列として返す.
- next():改行または空白文字の手前までを一つの文字列として返す.改行または空白文字は消えない.
- Eclipseで,コマンド引数を利用したい場合はEclipseでのプログラム開発の5節を読むこと.
- 入力のパターン処理を行いたい場合は,matches()メソッドで正規表現が使える.
import java.util.*;
public class Sample82a {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (true) {
try {
System.out.print("x> ");
String s =sc.nextLine();
Double x = Double.parseDouble(s);
System.out.print("y> ");
s =sc.nextLine();
Double y = Double.parseDouble(s);
System.out.printf("x + y = %.10f\n", x + y);
System.out.print("continue? ");
s = sc.nextLine();
if (!s.matches("^[yY]")) {
break;
}
} catch (Exception ex) {
System.out.println("? " + ex.toString());
}
}
sc.close();
}
}
8.2 ファイルやネットワークの入出力
- ファイルやネットワークの入出力もストリームとして扱うことができる.
- new File(ファイル名) : ファイルオブジェクトの生成
- new PrintStream(f) : fを出力ストリームとする
- new Scanner(f) : fを入力ストリームとする
- ストリームの利用を終了するとclose()すること.
- 以下のプログラムでは,"test.txt"というファイルが存在する場合には,上書きされるので注意が必要である.
import java.io.File;
import java.io.PrintStream;
public class FileWrite {
public static void main(String[] args) {
PrintStream pr = null;
try {
pr = new PrintStream(new File("test.txt"));
pr.println("2020.6.30 1000 食料品 生活費");
pr.println("2020.6.30 1500 文房具 学習費");
pr.close();
} catch (Exception ex) {
System.err.println(ex);
}
}
}
8.3 日本語の扱いと文字コード
- Javaでは様々な国の文字コード(character code)が扱える.
- Java内部ではUNICODEを採用している.これを内部エンコーディング(internal encoding)という.
- Java外部のファイルや入出力装置は独自の文字コードを採用している.これを外部エンコーディング(external encoding)という.
- Javaでは内部エンコーディングと外部エンコーディングの変換が可能である.
- new PrintStream(File, 文字セット名) : 文字セットを指定して出力ストリームを生成する.
- new Scanner(InputStream, 文字セット名) : 文字セット名を指定して入力ストリームを生成する.
- 日本語に関する文字セット名には以下のものがある.
- "JISAutoDetect" : JIS自動判別(正しく判別できないことがあるので注意)
- "ISO-2022-JP" : 7ビットJISコード
- "Shift_JIS" : Shift JISコード
- "EUC_JP" : 日本語EUCコード
- "UTF-8" : UNICODE UTF-8表現
- "UTF-16" : UNICODE UTF-16表現
8.4 例題:家計簿管理プログラム
- TreeMapはキー(鍵)が利用できるコンテナ(配列のようなもの)である.以下のメソッドが利用できる.
- put(キー,値)で,キーで指定される要素に値を設定する.
- get(キー)で,キーで指定される要素の値を得る.
- containsKey(キー)でキーで指定される要素があるかどうかを判定する.
- keySet()でキーの並びを得る.
- 事前に家計簿データファイルをエディタを用いて,作成しておく必要がある.文字コードはUTF-8にしておくこと.Eclipseでもテキストファイルの作成は可能である.
import java.util.*;
import java.io.*;
public class Sample83 {
static ArrayList<String> date = new ArrayList<String>();
static ArrayList<Integer> amt = new ArrayList<Integer>();
static ArrayList<String> item = new ArrayList<String>();
static ArrayList<String> kind = new ArrayList<String>();
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (true) {
try {
System.out.print("command> ");
String[] cmd = sc.nextLine().split("[ \t]+");
if (cmd.length == 0) {
} else if (cmd[0].equals("exit")) {
sc.close();
System.exit(0);
} else if (cmd[0].equals("read")) {
if (cmd.length < 2) {
System.out.println("Usage: read <filename>");
continue;
}
read(cmd[1]);
} else if (cmd[0].equals("print")) {
PrintStream pr = System.out;
if (cmd.length > 1) {
pr = new PrintStream(new File(cmd[1]), "UTF-8");
print(pr);
pr.close();
} else
print(pr);
} else if (cmd[0].equals("sum")) {
PrintStream pr = System.out;
if (cmd.length > 1) {
pr = new PrintStream(new File(cmd[1]), "UTF-8");
sum(pr);
pr.close();
} else
sum(pr);
} else {
System.out.println("Unknown command: " + cmd[0]);
}
} catch (Exception ex) {
System.out.println("? " + ex.toString());
}
}
}
public static void read(String f) throws Exception {
Scanner sc = new Scanner(new File(f), "UTF-8");
int lineno = 0;
System.out.println(f);
while (sc.hasNextLine()) {
String line = sc.nextLine();
System.out.println(line);
++lineno;
String[] a = line.split("[ \t]+");
try {
String d = a[0], i = a[2], k = a[3];
int m = Integer.parseInt(a[1]);
date.add(d);
amt.add(m);
item.add(i);
kind.add(k);
} catch (Exception ex) {
System.out.printf("line %d: spurious line: '%s'\n", lineno, line);
}
}
sc.close();
}
public static void print(PrintStream pr) throws Exception {
for (int i = 0; i < date.size(); ++i) {
pr.printf("%-8s %8d %s %s\n", date.get(i), amt.get(i), item.get(i), kind.get(i));
}
}
public static void sum(PrintStream pr) throws Exception {
TreeMap<String, Integer> tbl = new TreeMap<String, Integer>();
for (int i = 0; i < date.size(); ++i) {
int a = amt.get(i);
int t = 0;
if (tbl.containsKey("TOTAL")) {
t += tbl.get("TOTAL");
}
tbl.put("TOTAL", t + a);
String k = kind.get(i);
t = 0;
if (tbl.containsKey(k)) {
t += tbl.get(k);
}
tbl.put(k, t + a);
}
for (String k : tbl.keySet()) {
pr.format("%s = %d\n", k, tbl.get(k));
}
}
}
付録:正規表現
- 文字列のパターンを指定する標準的な方法として正規表現がある.
- サルにもわかる正規表現入門
- 例:"^こんにち[わは]"は,「こんにちは」または「こんにちわ」ではじまる文字列とマッチする.
- "^"は文字列の先頭を表す.
- "[AB]"はAまたはBを表す.
- 例:"[ \t]+"は,空白またはタブ(\t)の1回以上の繰り返し(+)となる文字列とマッチする.
ykitamura@kwansei.ac.jp