【c#】csvでデータを保存しとくなら、読み込んだあとのチェックは必須

↓よく、こんなケースがある。

①. アプリ内で扱ってるデータをcsv形式で保存しとく
②. csvを読み込む
③. ②で読み込んだデータのうち、特定の位置ものをつかう

こーゆーとき、③の前に「データを読み込めたか」のチェックは必ず実装しよう。

csv形式のデータは、思わぬところで読み込めない場合がちょこちょこある。


コード

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace testNameSpace
{
    class testClass
    {
        const int USE_DATA_INDEX = 2;    //使いたいデータの位置
        
        public void testMethod()
        {
            // アプリ内で扱ってる、intデータのList
            List<int> nList = new List<int>();
            Random r = new System.Random();

            for(int n = 0; n < 10; n++)
            {
                nList.Add(r.Next(10));  //仮の値を10個ほど
            }

            // csvに保存するために , 区切りでstring化
            string strWrite = "";
            foreach(int n in nList)
            {
                strWrite += n.ToString();
                strWrite += ",";
            }

            Console.WriteLine("csvに書き込むデータ:" + strWrite);

            DateTime dtWrite = DateTime.Now;    //今日の日付のディレクトリに保存

            csvWrite(strWrite, dtWrite);

            DateTime dtRead = DateTime.Now;    //今日の日付のディレクトリから読み込み

            string strRead = csvRead(dtRead);

            Console.WriteLine("csvから読み込んだデータ:" + strRead);

            List<int> nListRead = new List<int>();

            string[] strArr =  strRead.Split(',');
            
            foreach(string str in strArr)
            {
                int n = 0;
                if(int.TryParse(str, out n))
                {
                    nListRead.Add(n);
                }
            }
            
            int nUseData = nListRead[USE_DATA_INDEX];

            Console.WriteLine("csvから読み込んで使いたい特定のデータ:" + nUseData);

        }

        protected void csvWrite( string str, DateTime dt )
        {
            string  strDirPath = string.Join( "\\", "D:", ( dt.ToString("yyyyMMdd") ) );
            if( !( System.IO.Directory.Exists( strDirPath ) ) )
            {
                System.IO.Directory.CreateDirectory( strDirPath );
            }

            string  strFilePath = string.Join( "\\", strDirPath, "test.csv" );
            using ( StreamWriter sWriter = new StreamWriter( strFilePath, false ) )
            {
                sWriter.WriteLine( str );
            }

            return;
        }

        protected string csvRead( DateTime dt )
        {
            string    str   =   "";

            string  strDirPath     =   string.Join( "\\", "D:", ( dt.ToString("yyyyMMdd") ) );
            if( !( System.IO.Directory.Exists( strDirPath ) ) )
            {
                return  str;
            }

            string  strFilePath    =   string.Join( "\\", strDirPath, "test.csv" );
            if( !( System.IO.File.Exists( strFilePath ) ) )
            {
                return  str;
            }

            using ( StreamReader sReader = new StreamReader( strFilePath ) )
            {
                str = sReader.ReadLine();
            }

            return str;
        }
    }
}

出力

csvに書き込むデータ:8,7,5,8,3,8,7,4,0,8,
csvから読み込んだデータ:8,7,5,8,3,8,7,4,0,8,
csvから読み込んで使いたい特定のデータ:5

こんなカンジで、アプリ内で扱うデータをいったんcsvにしておいて、あとから読み込んで特定のデータを使うとしよう。

で、このコードでは《特定のデータ》を抜きだすために、indexを定数で持ってる。

        const int USE_DATA_INDEX = 2;    //使いたいデータの位置

この定数をもってて、

            int nUseData = nListRead[USE_DATA_INDEX];

こーやってデータを抜きだす。

と。

でも、もしも

            DateTime dtRead = DateTime.Now;    //今日の日付のディレクトリから読込み

            string strRead = csvRead(dtRead);

ここらへんで

            DateTime dtRead = DateTime.Now.AddDays(1);

            string strRead = csvRead(dtRead);

こんなことが起こると、

※実際はこーゆーコードを書いてしまうというより《処理中に日付が変わってズレたり》とか《うるう年の考慮がなかった》とか、それ系のまちがいな。

出力

csvに書き込むデータ:1,0,3,3,8,7,6,8,4,6,
csvから読み込んだデータ:
'System.ArgumentOutOfRangeException' の初回例外が mscorlib.dll で発生しました。

ドドン。例外が発生する。

理由はとうぜん、

            int nUseData = nListRead[USE_DATA_INDEX];

ここで《値がないリストに対して要素番号を指定してるから》だな。

こーゆー使い方をするときは、

            int nUseData = 0;
            if(nListRead.Any())
            {
                nUseData = nListRead[USE_DATA_INDEX];
            }

LinqのAny()あたりでチェックしてやろう。

まぁAny()は「配列とかリストが空かどうかを判定」するメソッドだから、もっというと、指定する要素数の位置までデータが埋まってるかもチェックしたいところだけどな。

せめて、最低でも、この程度はチェックしとこう。

わりとcsvは思わぬ落とし穴があったりするんでね。

これマジ。