ラベル using の投稿を表示しています。 すべての投稿を表示
ラベル using の投稿を表示しています。 すべての投稿を表示

2018年3月14日水曜日

CSVのデータを変数に一旦格納、型変換して描画処理を行います

CSVファイルを読めるようになったら、次は各フィールドのデータを、後で使いやすいようにどこかにしまっておく必要があります。

普通に考えるとしまっておくのに最適な場所は配列ではないかと考えると思います。しかし、今回のプログラムはデータの大きさが既知ではないことを想定しています。通常の配列は宣言時にデータの大きさを宣言しなければならず、通常の配列は使えないと当初から思っていました。

データの大きさが決まっていないような場合に、動的にサイズを変える仕組みがある入れ物はないだろうか?と考えて、探してみたら、C#にはArrayListというものがあります。前のエントリーでちょっと出て来ましたね。

前回のエントリーに出てきたプログラムを改造して、TextFieldParserで分割したフィールドデータをArrayListに格納していくコードを作成しました。動かした結果は前回と同じですが、内部的にはArrayListの行を追加しながら画面にも表示する、という動作になっています。詳細は、プログラム中のコメントをご覧下さい。

なお、CSVファイルの中身ですが、1行の作りが

測定点のX座標,測定点のY座標,測定点のZ座標,測定点のデータ本体

という作りになっています。1行に測定点1点分のデータが入っており、測定点の数だけ行がある、という構造です。今回のプログラム評価用のデータは、全て整数です。

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.VisualBasic.FileIO;

namespace getDataFromCSV
{
    class Program
    {
        //string line = "";
        //ArrayList al     = new ArrayList();
        public static ArrayList x_axis = new ArrayList(); // X軸データ用ArrayList
        public static ArrayList y_axis = new ArrayList(); // Y軸データ用ArrayList
        public static ArrayList z_axis = new ArrayList(); // Z軸データ用ArrayList
        public static ArrayList dt = new ArrayList(); // データ本体用ArrayList

        static void Main(string[] args)
        {
            getData("c:\\users\\gustav\\検討用テストデータ.csv");

            Console.ReadKey();
        }

        static void getData(string file)
        {
            try
            {
                using (
                    TextFieldParser parser =
                    new TextFieldParser(file, System.Text.Encoding.GetEncoding("Shift_JIS"))
                    )
                {
                    parser.TextFieldType = FieldType.Delimited;
                    parser.SetDelimiters(","); // 区切り文字はコンマ
                    parser.CommentTokens = new string[1] { "#" };
                    int line = 0, col = 0;

                    while (!parser.EndOfData)
                    {
                        string[] row = parser.ReadFields();
                        x_axis.Add(row[0]);  // ここでArreyListの行を追加
                        y_axis.Add(row[1]);
                        z_axis.Add(row[2]);
                        dt.Add(row[3]);

                        Console.Write(line + " : ");  //画面出力
                        Console.Write("X=" + (string)x_axis[line]);  // メンバーの参照はこのように行う
                        Console.Write(" | Y=" + (string)y_axis[line]);
                        Console.Write(" | Z=" + (string)z_axis[line]);
                        Console.Write(" | DATA=" + (string)dt[line]);
                        Console.WriteLine(" ");

                        ++line;
                    }
                    Console.WriteLine("Line 3236 " + (string)dt[3235]);
                    // 行番号とデータが合っているかどうかの確認用
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }
    }
}

これでCSVから各フィールドのデータをstringデータながら拾い上げて配列におさめることができるようになりました。

今回は、さらにこの後、データを適切に型変換して、実際に使って見るところまで進めたいと思います。

以下のリストは、以下の処理をしています。

  • CSVファイルからデータを読み出して、配列に格納
  • 配列データを順に読んで、型変換を行う。(TextFieldParserはstring型のデータを返す仕様)
  • 型変換したデータに対して、座標データはデータが持つ座標系とウインドウの座標系の変換を行う(ウインドウの座標で描画しなければならない)
  • データ本体は、データの中身に応じて描画するピクセルの色を割り当てる
  • 上記で得られたデータを使って、X座標とY座標とデータの中身でBitmapオブジェクトに描画
  • PictureBoxのImageプロパティにBitmapを設定
  • マウスカーソルの座標を取得し続け、ウインドウの上部に座標を表示
座標系の変換ですが、特に難しい変換は不要で、単なる足し算です。Form上のPictureBoxの持つ座標系は左上の頂点が原点となります。これに対して、データの持つ座標系はでは、PictureBoxの都合の良い場所に、例えば図のような場所に置くことになると思います。

データは、あくまでも図のデータ座標系座標原点の場所が原点となっているデータなので、それをPictureBoxの座標系に変換するには、データ座標系の原点のPictureBox内に於ける座標を加えてあげれば変換できます。

このプログラムでは、Program.cs内のstatic class Constantsで計算の為のオフセット値を定数として定義しています。

また、マウスカーソルの座標を取得し続ける処理では、PictureBox座標をデータ座標に変換してから、ウインドウに表示しています。この処理も考え方は同じで、PictureBox座標で取得されるマウスカーソル座標からオフセット分を引き算して、データ座標を求めています。

ファイルProgram.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;


namespace CSVtoData
{
    static class Constants  // Mainメソッドが入っているファイルで、定数の定義をしています。
    {
        public const string FileName = "c:\\users\\gustav\\検討用テストデータ.csv";
        public const int offset_x = 640 / 2;
        public const int offset_y = 500;
        public const int offset_z = 0;

    }

    static class Program
    {
        /// 
        /// アプリケーションのメイン エントリ ポイントです。
        /// 
        [STAThread]

        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }
}

ファイルForm1.cs
using System;

using System.Collections.Generic;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.VisualBasic.FileIO;

namespace CSVtoData
{
    public partial class Form1 : Form
    {
        public static int mouse_x = 0, mouse_y = 0;  // このForm1クラスの中で、広域的に参照できるようにこの定義方法です。

        public static ArrayList x_axis = new ArrayList();
        public static ArrayList y_axis = new ArrayList();
        public static ArrayList z_axis = new ArrayList();
        public static ArrayList dt = new ArrayList();

        public Form1()
        {
            InitializeComponent();

            this.MaximumSize = this.Size;
            this.MinimumSize = this.Size;

            Bitmap img = new Bitmap(600, 720);

            Color col = new Color();

            try
            {
                using (TextFieldParser parser =
                    new TextFieldParser(Constants.FileName, System.Text.Encoding.GetEncoding("Shift_JIS")))
                {
                    parser.TextFieldType = FieldType.Delimited;
                    parser.SetDelimiters(","); // 区切り文字はコンマ
                    parser.CommentTokens = new string[1] { "#" };
                    int line = 0;

                    while (!parser.EndOfData)
                    {
                        //++line;
                        //col = 0;

                        string[] row = parser.ReadFields(); // 1行読んで、要素に分解、配列rowに格納

                        x_axis.Add(row[0]);  // ArrayListにX軸座標を追加
                        y_axis.Add(row[1]);  // ArrayListにY座標を追加
                        z_axis.Add(row[2]);  // ArrayListにZ座標を追加
                        dt.Add(row[3]);      // ArrayListにデータ本体を追加
                        ++line;
                    }
                }
            }
            catch (Exception e)  // TextFieldParser処理中にエラーが出たら、エラーメッセージを出してプログラム終了
            {
                MessageBox.Show(e.Message);
                Environment.Exit(0); // 強制終了
            }

            for (int i = 0; i < x_axis.Count; ++i)
            {
                int x = (int)Convert.ToDouble(x_axis[i]) + Constants.offset_x;  // 座標データの型変換とオフセット加算
                int y = -1 * ((int)Convert.ToDouble(y_axis[i])) + Constants.offset_y;
                int z = (int)Convert.ToDouble(z_axis[i]) + Constants.offset_z;
                int d = (int)Convert.ToDouble(dt[i]);

                switch (d)  // ここでデータ本体と色の結びつけをしています。
                {
                    case 0:
                        col = Color.Black;
                        break;
                    case 1:
                        col = Color.Blue;
                        break;
                    case 2:
                        col = Color.Red;
                        break;
                    case 3:
                        col = Color.Purple;
                        break;
                    case 4:
                        col = Color.Green;
                        break;
                    case 5:
                        col = Color.Yellow;
                        break;
                    case 6:
                        col = Color.Violet;
                        break;
                    case 7:
                        col = Color.White;
                        break;
                    default:
                        col = Color.Magenta;
                        break;
                }

                img.SetPixel(x, y, col);  // データがCSVに入っている順番で、プロットします。
            }
            pictureBox1.Image = img;
        }
        // MouseMoveイベントハンドラー
        private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
        {
            getMousePosition();
        }

        private void getMousePosition()  // このメソッドは、マウスの座標を取得し続けるエントリーで出てきたものそのまま。
        {
            if (this.Focused)
            {
                System.Drawing.Point cp = pictureBox1.PointToClient(Cursor.Position);

                mouse_x = cp.X - Constants.offset_x;
                mouse_y = -1 * cp.Y + Constants.offset_y;

                label1.Text = "Focused";
                this.Text = "x=" + mouse_x + ":y=" + mouse_y;
            }
            else
            {
                mouse_x = mouse_y = (int)0xffff;
                label1.Text = "Not Focused";
                this.Text = "x=" + mouse_x + ":y=" + mouse_y;
            }

        }
    }
}


ファイルForm1.Designer.cs
このリストは、Visual Studioが自動的に吐き出すもので、使用されるイベントや各コントロールのプロパティが記述されています。このファイルがないと、ビルドができません。内容は特に説明しませんが、PictureBox1の最後の行が、PictureBox1.MouseMoveイベント関連の記述です。

namespace CSVtoData
{
    partial class Form1
    {
        /// 
        /// 必要なデザイナー変数です。
        /// 
        private System.ComponentModel.IContainer components = null;

        /// 
        /// 使用中のリソースをすべてクリーンアップします。
        /// 
        /// マネージ リソースを破棄する場合は true を指定し、その他の場合は false を指定します。
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows フォーム デザイナーで生成されたコード

        /// 
        /// デザイナー サポートに必要なメソッドです。このメソッドの内容を
        /// コード エディターで変更しないでください。
        /// 
        private void InitializeComponent()
        {
            this.pictureBox1 = new System.Windows.Forms.PictureBox();
            this.label1 = new System.Windows.Forms.Label();
            ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
            this.SuspendLayout();
            // 
            // pictureBox1
            // 
            this.pictureBox1.Location = new System.Drawing.Point(12, 9);
            this.pictureBox1.Name = "pictureBox1";
            this.pictureBox1.Size = new System.Drawing.Size(600, 703);
            this.pictureBox1.TabIndex = 0;
            this.pictureBox1.TabStop = false;
            //this.pictureBox1.MouseHover += new System.EventHandler(this.pictureBox1_MouseHover);
            this.pictureBox1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.pictureBox1_MouseMove);
            // 
            // label1
            // 
            this.label1.AutoSize = true;
            this.label1.Font = new System.Drawing.Font
                    ("MS UI Gothic", 11.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(128)));
            this.label1.Location = new System.Drawing.Point(271, 728);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(43, 15);
            this.label1.TabIndex = 1;
            this.label1.Text = "label1";
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(624, 761);
            this.Controls.Add(this.label1);
            this.Controls.Add(this.pictureBox1);
            this.Name = "Form1";
            this.Text = "Form1";
            ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion

        private System.Windows.Forms.PictureBox pictureBox1;
        private System.Windows.Forms.Label label1;
    }
}

上記プログラムを実行すると、このようなウインドウが出ます。見にくいですが、ウインドウの中に、小さな点が沢山描画されていて、それで四角形を形成しているのがわかります。

そして、ウインドウ左上に、マウスカーソルの座標が表示され続けます。

これで、目標仕様を実現するための要素技術として、


  1. ウインドウに点が打てる
  2. ファイルの読み出しが出来る
  3. ウインドウ上にあるマウスの座標が読み取れる
  4. ウインドウの座標系とデータの座標系の変換ができる

と、6項目中4項目が実現出来ています。

今回はここまでにします。


2018年3月13日火曜日

CSVファイルの処理方法について

目標としているプログラムでは、データはCSV形式のファイルで渡されることを前提にしているので、CSVファイルを読み込んで、CSVデータの解釈をして、分解したデータを適切な変数に格納する、という動作が必要となります。

CSVとは、comma-separated valuesの略で、いくつかのフィールド(項目)を区切り文字であるカンマで区切ったテキストデータおよびテキストファイルのことです。(Wikipediaより)
、読んだテキストを分解する、ということができれば、あとはデータ変換をして変数に格納、とう流れに持って行けると思います。

このような処理は、たとえばawkだとsplitを使って文字列分割をするとか、perlだと正規表現を使って数値を拾うといった処理を使うと簡単です。たとえば,
0,200,-100,8
0,195,-100,8
0,190,-100,8
0,185,-100,8
0,180,-100,8
0,175,-100,8
0,170,-100,8
0,165,-100,8
0,160,-100,8
0,155,-100,8
といったCSVファイルがある場合、perlの場合だと

/^(-?\d+\.?\d*),(-?\d+\.?\d*),(-?\d+\.?\d*),(-?\d+\.?\d*)/

で括弧内の正規表現を入力の数値にマッチさせてあげると、変数$1、$2、$3、$4にそれぞれ順番に各フィールドの数値が入ります。

#/usr/local/bin/perl
$cnt = 0;
while(<>) {
    if( /^(-?\d+\.?\d*),(-?\d+\.?\d*),(-?\d+\.?\d*),(-?\d+\.?\d*)/ ) {
        printf( "%04d : %f : %f : %f : %f\n", $cnt++, $1, $2, $3, $4 );

    }

}

このスクリプトは、CSVファイルの各フィールドを拾い上げて、画面に出力してくれるものです。私が書いているもう一つのブログ、「半導体やってました」で紹介しています。

実は、後で調べたらC#にもsplitや正規表現によるMatchesなどというものが用意されているみたいです。これは後日研究してみることにしたいと思います。

さて、正規表現やsplitメソッドがあることを知らなかった私は、インターネットを検索して、面白いものを見つけました。それはTextFieldParserというもの。これは、Visual Basicが持っているCSVのパーサーを呼び出して、CSVを解釈しようというものです。

上に書いた正規表現によるフィールドの分割は、各フィールドの文字列がしっかりと正規表現にマッチしないとうまく動いてくれません。たとえば、上の正規表現の例では、コンマの前後にスペースがあったらマッチしません。

それに対して、CSVファイルというものは、意外に表記方法にバラツキがあって、そのバラツキが正規表現でカバーできる範囲を超えてしまうとうまく動かなくなってしまいます。それに対して、このTextFieldParserは、かなり広範囲にわたってCSVファイルを適切に解釈してくれるもののようです。フィールドの数に動作が左右されることもありません。

下記は、TextFieldParserを使ってCSVファイルの各行をフィールド分割し、

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading.Tasks;
using System.Collections;
using Microsoft.VisualBasic.FileIO;

namespace sample
{
    class Program
    {
        static void Main(string[] args)
        {
            string line = "";
            getDataFromCSV("c:\\users\\ぐすたふ\\検討用テストデータ.csv");

            Console.ReadKey();
        }

        static void getDataFromCSV(string file)
        {
            try
            {
                TextFieldParser parser =
                     new TextFieldParser(file, System.Text.Encoding.GetEncoding("Shift_JIS"));
                parser.TextFieldType = FieldType.Delimited;
                parser.SetDelimiters(","); // 区切り文字はコンマ
                parser.CommentTokens = new string[1] { "#" };
                int col = 0;

                while (!parser.EndOfData)
                {
                    col = 0;

                    string[] row = parser.ReadFields();
                    Console.Write("{0} : ", line);
                    // 配列rowの要素は読み込んだ行の各フィールドの値
                    foreach (string field in row)
                    {
                        ++col;
                        Console.Write("{0}:{1} | ", col, field);
                    }
                    ++line;
                    Console.WriteLine(" ");
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }
    }
}

これは、区切り文字をコンマ、行頭が#の行はコメントであることをパーサーに指示して、CSVフィアルを解釈し、

行番号:フィールド番号:フィールドの中身 | フィールド番号:フィールドの中身 | ・・・

の形でデータをコンソールに出力します。

今回の主役であるTextFieldParserですが、解説のページを見るとわかるようにコンストラクタが8種類あります。引数の型や数に応じて異なるコンストラクタが動作するようになっています。

上記の例では、

TextFieldParser( string, Encoding )

を使用しています。stringは、入力ファイルの完全なパス、Encodingは文字エンコードで、上の例ではShift_JISを指定しています。

オブジェクトを生成したのち、

  • プロパティTextFieldTypeにFieldType.Delimitedを指定(可変長レコード)
  • プロパティSetDelimitersでフィールドの区切りを","に指定
  • プロパティCommentTalkenでコメント指定文字を"#"に指定

しています。FieldType.Delimitedは、名前空間Microsoft.VisualBasic.FileIOで定義された列挙体です。

そのあと、ReadField()メソッドでファイルから1行読み込んで解析を行い、配列rowにそれぞれのフィールドを代入して戻ってくる、という仕組みになっています。

なお、このTextFieldParserにはDisposeメソッドがあります。したがって、本来は、解析が終了したら、不要になったリソースを開放する必要があります。finallyでファイルをクローズしてDispose()を呼び出すか、usingを使うのが良いと思います。このことは、原稿を書いているときに気が付いたので、上記プログラムはusingを適用しないままのものを出しています。

usingで対応するとすれば、以下のようにすればよいのでしょうか。エラーなしでビルドできて、動作も問題なくできています。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading.Tasks;
using System.Collections;
using Microsoft.VisualBasic.FileIO;

namespace sample
{
    class Program
    {
        static void Main(string[] args)
        {
            string line = "";

            getDataFromCSV("c:\\users\\gustav\\検討用テストデータ.csv");

            Console.ReadKey();
        }

        static void getDataFromCSV(string file)
        {
            try
            {
                using (TextFieldParser parser = 
                    new TextFieldParser(file, System.Text.Encoding.GetEncoding("Shift_JIS")))
                {
                    parser.TextFieldType = FieldType.Delimited;
                    parser.SetDelimiters(","); // 区切り文字はコンマ
                    parser.CommentTokens = new string[1] { "#" };
                    int line = 0, col = 0;

                    while (!parser.EndOfData)
                    {
                        //++line;
                        col = 0;

                        string[] row = parser.ReadFields();
                        Console.Write("{0} : ", line);
                        // 配列rowの要素は読み込んだ行の各フィールdの値
                        foreach (string field in row)
                        {
                            ++col;
                            Console.Write("{0}:{1} | ", col, field);
                        }
                        ++line;
                        Console.WriteLine(" ");
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }
    }
}

usingは書き方にクセがあって、あまり美しくないのが気に入りませんが、仕方ないでしょう。

今回はここまでにします。

2018年3月12日月曜日

テキストファイルの読み込み

画面表示とマウスカーソルが一段落付いたので、データを読み込む為の要素技術である、ファイルの読み込みの学習を始めました。

昔のCであれば、テキストファイルを読み込んで画面表示しようとしたら、
#include <stdio.h>
#define MAXLINE 256

FILE *fp;
char *fname = "file.txt";
char readline[MAXLINE];

if( (fp = fopen( fname, "r" ) ) == NULL ) {
 fprintf( stderr, "file %s cannot open.\n", fname );
 exit(-1);
}

whiel( fgets( readline, MAXLINE, fp ) != NULL ) {
 fputs( readline );
}

fclose( fp );

等と言うことになるんだと思います。上記についてはあえて詳しく説明はしませんが、file.txtというファイルをオープンして、1行ずつ読み込み、標準出力に1行ずつ出力するというものです。unixのキャラクタベースの世界だと、あえてファイルオープンをせずに、標準入力から入力を読む、というコードにしておいて、入力をファイルにリダイレクトする、というような思想で書くことが多かったと思います。

C#でテキストファイルをオープンして読み込む方法を探したら、以下のようなものが見つかりました。

下記リストは、とあるCSVファイルをオープンして、ファイルを1行ずつ読んで配列に格納し、格納し終わったらコンソールに出力しています。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading.Tasks;
using System.Collections;


namespace read1line
{
    class Program
    {
        static void Main(string[] args)
        {
            string line = "";
            ArrayList al = new ArrayList();

            try {
                using (StreamReader sr = new StreamReader("c:/users/ぐすたふ/検討用テストデータ.csv",
                    Encoding.GetEncoding("Shift_JIS")))
                {
                    while((line = sr.ReadLine()) != null)  // ファイルを1行ずつ読んで配列alに格納
                    {
                        al.Add(line);
                    }
                }
            }
            catch (Exception e )
            {
                Console.WriteLine(e.Message);  // 例外が発生したら、コンソールにメッセージを出力
            }

            for( int i = 0; i < al.Count; i++ )  // alを1行ずつコンソールに出力
            {
                Console.WriteLine(al[i]);
            }
            Console.WriteLine("readed " + al.Count + "lines");
            Console.ReadKey();
        }
    }
}

ここで、 StreamReaderはSystem.IO名前空間に属するクラスです。文字コードを指定して、テキストファイルを読み込むためのクラスです。マイクロソフトの解説ページはこちらです。

いつものように機械翻訳で意味が分かりにくいので、もっとわかりやすく解説したページはこちらです。いつも勉強させていただいているdobon.net様です。

                using (StreamReader sr = new StreamReader("c:/users/ぐすたふ/検討用テストデータ.csv",
                    Encoding.GetEncoding("Shift_JIS")))

のコードで、ファイルを読み込む為のオブジェクトを生成しています。この中でファイルをオープンして文字コードの指定をしています。

                    while((line = sr.ReadLine()) != null)  // ファイルを1行ずつ読んで配列alに格納

の、StreamReader.ReadLine()(リスト中ではsr.ReadLine())は、テキストを1行読み込むメソッドです。

なお、リスト中に出てくるArrayListは、動的に大きさを拡大することが可能な配列を提供するクラスです。リストの冒頭に、テキストを読み込んで配列に格納する、と書きましたが、サイズが未知のテキストファイルを1行ずつ配列に読み込む為に、このArrayListを使っています。

ArrayListの説明はこちらにあります。

今度は、ファイルを最後まで一気にstring型の変数に読み込んで、一気にコンソールに出力しています。

/*
 * テキストファイルを一気に読み込む
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            string text = "";
            try
            {
                using (StreamReader sr = new StreamReader("c:/users/ぐすたふ/検討用テストデータ.csv", 
                            Encoding.GetEncoding("shift-jis")))
                {
                    text = sr.ReadToEnd();  // ファイルを一気に最後まで読んで、textに格納
                }
                Console.Write(text);  // textをコンソールに一気に出力
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);  // 例外が発生したら、コンソールにメッセージを出力
            }

            Console.ReadKey();
        }
    }
}



こちらで出てくる

                    text = sr.ReadToEnd();  // ファイルを一気に最後まで読んで、textに格納

の中のStreamReader.ReadToEnd()(リスト中ではsr.ReadToEnd())は、ファイルの現在の場所からファイルの最後までを一気に読み込むメソッドです。


上記2つのリストでは、いずれの例も、usingステートメントと、try 〜 catchステートメントを使っています。

usingステートメントは、マイクロソフトのこのページに説明がありますが、機械翻訳なので全くわかりませんね。このページ(C# Tips様)このページ(プログラムマーズ雑記帳様)を読むと、もう少しわかりやすいと思います。

C#のクラスには、使い終わった後にDisposeメソッドを使ってリソースを開放しなければならないものがあります。

しかし、例外の発生によってDisposeの呼び出しが適切なタイミングでできないような場合、動作に矛盾が生じてしまう場合があるようです。それを防ぐ為、適切なDisposeを確実に行ってくれるようにするのがusingである、と書いてあります。

ファイルを扱う場合は、usingを使うのが安全だそうです。

また、try 〜 catchは例外処理を行う為のステートメントです。こちら(++C++; //未確認飛行C様)に説明があります。正しくは、try 〜 catch 〜 finallyで、

try {
  例外を発生する可能性があるコード
}
catch( 例外の種類 ) {
  例外処理をするコード
}
finally {
  例外の有無にかかわらず実行させたいコード
  リソースの開放などに使う
}

という書き方をします。

それで、上記のプログラムの例だと、usingを使ってファイル操作をしているので、finallyでリソースの開放をしなくても済んでいる、ということですね。

今回はこれで終わりにします。