【C#】実例:CSVファイル読み込みでパラメータ設定

スポンサーリンク

今回はちょっと実際に使う方法を意識したブログを作っていきたいと思います。
仕事の都合上、『パラメータを読み込む』ことが必然的に多くあります。

基本的には「configファイル読み込み」や「iniファイル読み込み」や「xmlファイル読み込み」といった方法がよく使われる方法でしょう。

しかし、今回は『CSVファイルの読み込みでパラメータ読み込み』を作った場合どうなるかをやってみようと思います。
今回、紹介する内容(要素)が多いため、少し長くなります。
また、自分だったらこうする』という紹介の為、手段の一つだと思ってください。

作成手順について

流れとしては、下記で紹介していきます。

1.CSVファイルのフォーマットを決める
2.CSVファイルをプロジェクトに含める
3.CSVファイルを編集&コンパイル時に出力設定
4.変数定義(列挙体とディクショナリ型)
5.CSVファイル読み込みし、ディクショナリに登録

CSVファイルのフォーマットを決める

CSVファイルのフォーマットを決める

最初のstepとして、ファイルの仕様を決めたいと思います。

1行目は、ヘッダーを置きます。
※この行は、読み込みの対象外
2行目以降にデータを入力とします。

1列目は、『Key(変数名)』とします。
2列目は、『Value(値)』とします。

CSVファイルをプロジェクトに含める

CSVファイルをプロジェクトに含める

ファイルフォーマットを決めたので、それに従ってファイルを作成してみました。

VisualStudio上で「csvファイルを作成」したので、手順を紹介します。
[プロジェクトを選択]状態で右クリック→[追加]→[新しい項目]

[テキストファイル]→[名前]を任意で拡張子をcsvにする→[追加]
※今回のファイル名は『Parameter.csv』

すると、プロジェクトにcsvファイルが追加される。

CSVファイルを編集&コンパイル時に出力設定

CSVファイルを編集

VisualStudio上で編集可能です。
作成したファイルをダブルクリックすると編集が可能です。
※編集しづらい人は、エクセルから開く事をオススメします。

ファイル仕様通りに、1行目は、ヘッダーを作成しました。
下記コピペ用に内容を記載します。
keyとvalueの間には「 , 」をいれます。

key,value
test,100
hoge,30.2
str,param

CSVファイルをコンパイル時に出力設定

今編集したCSVファイルがコンパイルした時にEXEファイルと一緒に出力されるように設定します。
この設定は、CSVファイルに限った内容ではないので、コンパイル時に作成したファイルを出力したい場合は、同じやり方になります。

ソリューションウィンドウ内で、先ほど作成したCSVファイルを選択します。
選択をしたら、プロパティウィンドウを見てください
プロパティの中に【出力ディレクトリにコピー】という項目があります。
デフォルトでは、「コピーしない」となっているので、【常にコピーする】に変更しましょう。
この設定で、ビルドされるたびにプロジェクト内のファイルを一緒に出力するようになります。

変数の定義

ココからは、個人の作り方の話になってしまいます。
ただ1つの方法として、自分が作ってみた例なので、参考にしてもらえばと思います。

列挙体の定義

列挙体を定義します。
ここでは、CSVファイルのA列の項目(パラメータ名)を入れます。

enum ParamKey
{
    test,
    hoge,
    str,
}

ディクショナリを定義する

さきほど定義した列挙体を【Key】とし、パラメータの値を【Value】になるように定義します。

readonly Dictionary<ParamKey, object> Param = new Dictionary<ParamKey, object>();

起動したディレクトリを定義する

CSVファイルは、出力ディレクトリに出力される設定を先ほどしました。(ココ)
この出力ディレクトリを変数として定義します。
※VB6.0をしていた人ならAppPathとか言うと伝わるかもしれません。

readonly string AppPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

CSVファイル読み込みし、ディクショナリに登録

準備は整ったので、実際に出力されたcsvファイルを読み込みたいと思います。

CSVファイル読み込み

関数を作ります。
使うNameSpaceとしては、[ System.IO.StreamReader ]です。
これは、ファイル読み込みの時によく使うので覚えておきましょう!!

private void ReadParameterFile()
{
    string fp = AppPath + @"\Parameter.csv";

    Encoding encoding = Encoding.GetEncoding("Shift_JIS");
    using (StreamReader sr = new StreamReader(fp, encoding))
    {
        //ヘッダーをスキップ(1行読み込み)
        sr.ReadLine();

        //最終行まで読み込み
        while (sr.Peek() != -1)
        {
            //ここに読み込み処理
        }
    }
}

基本usingは、ファイルの上部で使用しますが、このような使い方も可能です。
[using]を関数の途中で使用するのは、限定的に動的なクラスを使用する事を明示しています。
使用後は、メモリが自動で解放されるので、単発的/限定的に使う場合はオススメです。

読み込んだ内容をディクショナリに登録する

読み込んだ内容の処理を記載していこうと思います。
サンプルのコードの【//ここに読み込み処理】の部分に記載していきます。

private void ReadParameterFile()
{
    string fp = AppPath + @"\Parameter.csv";

    Encoding encoding = Encoding.GetEncoding("Shift_JIS");
    using (StreamReader sr = new StreamReader(fp, encoding))
    {
        //ヘッダーをスキップ
        sr.ReadLine();

        //最終行まで読み込み
        while (sr.Peek() != -1)
        {
            string line = sr.ReadLine();
            string[] dts = line.Split(',');

            //文字列を列挙体に変換する
            ParamKey key = (ParamKey)Enum.Parse(typeof(ParamKey), dts[0]);
            object value = dts[1];

            //ディクショナリに登録
            Param.Add(key,value);
        }
    }
}

少し解説しておきます。

カンマで区切る

読み込んだ文字列は、下記のようになっています。

[文字列],[文字列]

csvファイルなのでカンマで区切る事で、keyとvalueに分ける事が出来ます。
string[] dts = line.Split(‘,’);
※任意の文字を区切り文字として指定する事は可能です。
こうする事で、dts[0]=key / dts[1]=value という状態になっています。

文字列を列挙体に変換(キャスト)する

今回定義したディクショナリのkeyは列挙体の為、変換する必要があります。
列挙体はクラスなので、型の変換と異なりますので、注意が必要です。
下記、構文で文字列から列挙体に変換する事が可能です。

( [定義した列挙体] )Enum.Parse(typeof( [定義した列挙体] ), [文字列])

この構文通り書くと、結果こうなります。
ParamKey key = (ParamKey)Enum.Parse(typeof(ParamKey), dts[0]);

ディクショナリに登録

定義したディクショナリに登録したい場合は、Add関数を使用します。
Param.Add(key,value);

実際にアプリケーションを作ってみました。

フォームとしては、keyをコンボボックスから選択し、その時の数値(Value)を表示します。

コンボボックスの選択肢を登録する

コンボボックスの選択肢(Item)は、列挙体の内容なので、コンボボックスに列挙体の内容を登録します。

private void SetComboBox()
{
    comboBoxKey.Items.Clear();
    comboBoxKey.Items.AddRange(Enum.GetNames(typeof(ParamKey)));
}

列挙体の要素名をすべて取得する

EnumクラスのGetNames関数を使用して、定義している列挙体の名前を取得します。
出力される型は文字列の配列(string[])になります。

Enum.GetNames(typeof(ParamKey))

出力された配列を、コンボボックスに登録します。
コンボボックスのItemsクラス内のAddRange関数を使用します。
この2つの関数(Enum.GetNames()とComboBox.Items.AddRange())を組み合わせいます。
その為、2つのことを1行でまとめて書いている事になります。

comboBoxKey.Items.AddRange(Enum.GetNames(typeof(ParamKey)));

コンボボックスが変化したら

イベントを作成します。
今回使用するイベントは【SelectedIndexChanged】というものです。
これは、コンボボックスの選択肢(Item)から何か選択された時に実行されます。

コンボボックスのテキストは文字列なので、文字列を列挙体に変換する必要があります。

private void ComboBoxKey_SelectedIndexChanged(object sender, EventArgs e)
{
    ParamKey key = (ParamKey)Enum.Parse(typeof(ParamKey), comboBoxKey.Text);
    labelValue.Text = Param[key].ToString();
}

コンストラクタ(初期化処理)

コンストラクタでは、今まで作っていた関数を実行させます。

public Form1()
{
    InitializeComponent();

    SetComboBox();  //コンボボックス設定

    ReadParameterFile();
}

まとめ

今回は、実例の記事を書いてみました。
実例になると、基礎の要素が多く発生します。
その為、ピンポイントの説明ではなくなるので、分かりづらくなりますね。
ただ、実際のやっている内容は基礎の組み合わせになります。
コード量も増えて読みたくないという気持ちは、共感しますw

今回のテーマだった「CSVファイルでパラメータ設定」は目的として達成できました。
これは、手段の1個でしかありません。
プログラムは十人十色だと思っていますので、参考になれば嬉しく思います。

最後に、今回作ったアプリケーションをダウンロードできるようにしておきます。
(ココをクリック)

コメント

タイトルとURLをコピーしました