Console入出力

コンソール画面の入出力

C#では「Console」というキーワードを用いて、コンソール画面への文字列を表示したり、ユーザーからのキー入力をプログラムに受け取ったりします。
(コンソール画面=背景が真っ黒で文字だけが表示されるアレ。標準入出力、コマンドプロンプト)
ここではコンソール入出力について簡単に説明します。

Console.WriteLine

今までのサンプルコードでも頻繁に使用している、コンソール画面に文字列を出力するメソッド(関数)です。
使い方は今まで説明してきた通り、出力したい値を引数に指定するだけです。


static void Main(string[] args)
{
    int num = 5;
    bool bo = true;
    string str = "abcde";

    Console.WriteLine(num);
    Console.WriteLine(bo);
    Console.WriteLine(str);

    Console.ReadLine();
}
5
True
abcde

上記コードではWriteLineメソッドの引数にint型、bool型、string型の変数をそれぞれ指定しています。

通常のメソッドは引数のデータ型は決められていて、それ以外のデータ型は受け付けてくれません。
しかしWriteLineメソッドはあらゆるデータ型をそのまま指定できます。
これはメソッドのオーバーロードという同じ名前のメソッドを複数定義できる機能を用いて実現しています。
(詳しくは上記ページで説明しています)

複合書式

WriteLineメソッドは引数を複数同時に取ることができます。
この時、第一引数には複合書式という特殊な文字列を指定します。
これは第二引数以降の値をどのような形式で表示するかを決定するための文字列です。


static void Main(string[] args)
{
    int num1 = 5, num2 = 7;

    Console.WriteLine("変数num1は{0}、変数num2は{1}", num1, num2);

    Console.ReadLine();
}
変数num1は5、変数num2は7

上記のようにすると、第二、第三引数の値が第一引数の文字列中に表示されます。

複合書式中の{0}{1}インデックスコンポーネント(単にインデックスとも)やパラメーター指定子といいます。
{0}は第二引数の値に、{1}は第三引数の値にそれぞれ置き換えられて表示されます。
これはいくらでも増やすことができますし、登場回数や順序も自由です。


int num1 = 5, num2 = 7;
string str = "abc";

//7, abc, 5, abc
Console.WriteLine("{1}, {2}, {0}, {2}",
    num1, num2, str);

ただし、インデックスに存在しない引数の番号を指定するとエラー(例外)となります。


//エラー
Console.WriteLine("{1}", 5);

複合書式についてはstring.Formatメソッドの項で詳しく解説しています。

Console.Write

コンソールへの文字列の出力はConsole.Writeメソッドも使用できます。
WriteLineメソッドとの違いは、出力の最後に改行が入らないという点だけです。
必要に応じて使い分けると良いでしょう。


Console.WriteLine("改行される");

Console.Write("改行されない");
Console.Write("改行されない");

Console.WriteLine(" ここで改行→");
改行される
改行されない改行されない ここで改行→

Console.ReadLine

文字の入力はConsole.ReadLineメソッドで行います。


static void Main(string[] args)
{
    Console.WriteLine("何か文字を入力してください。");

    string str = Console.ReadLine();
    Console.WriteLine("今入力した文字: {0}", str);

    Console.ReadLine();
}
何か文字を入力してください。
abcde
今入力した文字: abcde

赤字の斜体の箇所ユーザーのキーボード入力を示しています。
実際のプログラムの実行結果では色や書体は変わりません。

上記の実行結果は、上記コードを実行後にキーボードから「abcde」「Enter」と入力したところです。

ReadLineメソッドは引数がありません。
実行した時点でプログラムを停止させ、ユーザーからのキーボード入力を待ちます。
改行を一行と認識するので、エンターキーが押されると処理が続行されます。

戻り値は今キーボードから入力された文字列(string型)です。
string型なのでそのままstring型変数に代入できます。
キー入力の最後に改行がありますが、この改行は読み捨てられます。
(string型変数に代入しても最後に改行文字は入らない)

数字を入力しても「戻り値はstring型」であることに注意してください。
string型ですからそのまま四則計算等はできません。
string型をint型等に変換する方法はデータ型の相互変換を参照してください。

Console.Read

キーボード入力を受け取るメソッドはほかにもConsole.Readがあります。
これはWriteLineメソッドとWriteメソッドの関係と同じですが、単純に置き換え可能ではありません。

Console.Readメソッドの戻り値はint型となっており、そのまま文字列として使用することはできません。
これは文字コードというものです。
コンピュータは内部的に数値しか扱えませんから、文字も内部的には数字に置き換えられています。
例えば「a」は「97」、「b」は「98」...といった具合です。
これを文字として扱うにはchar型にキャストします。


int c = Console.Read();

Console.WriteLine(c);
Console.WriteLine((char)c);

Console.ReadLine();
a
97
a

キーボード入力が必要ならばReadLineメソッドを使用し、一文字が欲しいなら受け取った文字列をプログラム側で一文字ずつ分解するのが分かりやすくて良いでしょう。
Console.Readメソッドはこれ以外にも下記のようにいろいろと考慮しなければならないことが多く面倒くさいので、あまりお勧めしません。

標準入出力ストリーム

コンソール画面に入出力されるデータは、標準入出力ストリームという場所に一時的に保存された状態になります。
キーボードなどからの入力は標準入力ストリーム、ディスプレイなどへの出力は標準出力ストリームと言い、それぞれ独立しています
ストリームとは「流れ」のことで、入出力されるデータを一連の「流れ」と見立てた概念です。

標準入力はキーボード、標準出力はディスプレイですが、これは固定というわけではなく入出力先を変更することも可能です。
本サイトでは特に断りがない場合は標準入力はキーボード、標準出力はディスプレイとして説明しています。

■キーボードからの入力ストリームのイメージ図
入力ストリームのイメージ図

ユーザーからのキーボード入力は一時的に入力ストリーム内に保存されます。
エンターキーが押下(改行)されることで入力の終わりの合図となり、ストリーム内のデータがプログラム側に渡されます。

ReadLineメソッドの場合は最後の改行まですべて読み取ってしまうので、入力ストリーム内に文字は残りません。
しかしReadメソッドは一文字しか読み取りませんから、入力ストリーム内にデータが残る場合があります。

すると、以下のような現象が発生します。


static void Main(string[] args)
{
    int num1, num2;
    Console.WriteLine("何か文字を入力してください。");

    num1 = Console.Read();
    num2 = Console.Read();

    Console.WriteLine("{0}, {1}", num1, num2);

    Console.WriteLine("エンターキーで終了。");
    Console.ReadLine();
}
何か文字を入力してください。
abc

「abc」と文字を入力してエンターキーを押したとたん、プログラムは終了してしまいます。
正確に言えば一瞬何か文字が表示されますが、読む暇もないうちにコンソールウィンドウが閉じられます。

Console.Readメソッドは「入力ストリームから一文字読み取る」メソッドです。
入力ストリーム内にデータがない場合はユーザーからの入力待ちになりますが、すでにストリーム内にデータがある場合はキーボード入力待ちになることなくストリームから文字を読み取ります。

■キーボードからの入力ストリームのイメージ図
入力ストリームのイメージ図2

ユーザーが実際に何文字入力するかはわからないため、Readメソッドをうまく扱うにはループ文と組み合わせる必要があります。
(while文の項で再度説明します)
Readメソッドはこの処理が少し面倒なため、ReadLineメソッドのように気軽に使用できません。

入力ストリームにデータが残っている場合は入力待ちが起こらない、という動作自体はReadLineメソッドでも同じです。
しかしReadLineメソッドのみを使用している場合は入力ストリーム内にデータが残る状態になることはないため、特に気にすることなく連続して使用できます。