C# テキストファイルの保存 便利なCSV


ファイルの保存
NUll確認やファイルの存在確認を利用して細かくエラーハンドリングしながらファイル操作を行うのは色々と気を遣います。
Fileクラスで保存する場合、Windowsのように(1),(2),,,を末尾につけて自動でインデックスは振ってくれないので同名のファイルが存在していても平気で上書きします。そこで、ファイルがいたらインデックスをつけて新しくファイルを作る方法を紹介します。

string sの中身は「,」区切りの文字列であればよくCSVも同じテキストファイルなので拡張子をcsvにすればOK
あとは出来たファイルをExcelかGoogleSpreadSheetでインポートすれば素敵な表が瞬時に作れます。
メモ帳で開いて中身を確認することもできるのでデータの抜き取りやHTMLの解析などに使い勝手が良いです。
これだけのためにフォームアプリを利用する気にはならないのでコンソールアプリで開発するひとには必須です。

次のコードはメソッドで後からメイン側で呼び出せるようにしています。

sample.cs
using System;
using System.IO;


      private static void SaveFile(string s)
        {
            string DesktopDir = System.Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
            string FileName = "MJ_Resultlist";
            string Extend = ".csv";
            string FilePath = DesktopDir + "\\" + FileName + Extend;
            //上記の別の書き方
            //string FilePath = Path.Combine(DesktopDir,FileName) + Extend;
       //コメントでいただきましたメソッドです。フォルダ階層が深い場合は有効そうですね。


            int FileIndex = 0;

            //上書しないよう被らないファイル名になるまでループ
                while (File.Exists(FilePath) == true)
                {
                    FileIndex++;
                    FilePath = DesktopDir + "\\" + FileName + "(" + FileIndex.ToString() + ")" + Extend;
                }

            // 文字列をファイルに保存
            if (string.IsNullOrWhiteSpace(s) == false)
                File.WriteAllText(FilePath, s);
            else
                Console.WriteLine("ファイル保存失敗");
        }

引数sの中身の代入例としては 

sample1.cs
string s = "A" +","+ "B" +","+ "C";

と書いても良いですが、使い勝手が悪いので

sample2.cs
var list = new List<string>();
list.Add("A");
list.Add("B");
list.Add("C");
string s = string.join(",",list);
SaveFile(s);

//出力
/*********
A,B,C
*********/

のほうが見やすいです。また、CSVファイルの場合、改行コード"\n"を入れることで
段替えをおこなうことができます。

sample3.cs
var listA = new List<string>();
listA.Add("A1");
listA.Add("A2");
listA.Add("A3");

var listB = new List<string>();
listB.Add("B1");
listB.Add("B2");
listB.Add("B3");

var listC = new List<string>();
listC.Add("C1");
listC.Add("C2");
listC.Add("C3");

string A = string.join(",",listA);
string B = string.join(",",listB);
string C = string.join(",",listC);
string s = A + "\n" + B + "\n" + C;
SaveFile(s);

//出力
/*********
A1,A2,A3
B1,B2,B3
C1,C2,C3
*********/

ディレクトリの環境依存
提供先が誰に渡るか分からない場合、いちいちPCのユーザー名を聞き出してディレクトリにしてしまうのはよくありません。このソフトがどの環境で使用されてもいいようにSystemクラスには環境を呼び出すクラスが用意されています。次のコードは環境のデスクトップを呼び出しますのでどのPCでプログラムを実行してもそのデスクトップに保存されます。
System.Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory)

ここからフォルダを自動生成して中に保存することもできます。

呼び出し
ファイルの保存は基本的に非同期処理が好ましく、フォームアプリならプログラムのセッションはソフト終了まで続くので例えばセーブボタンを押してから保存完了まで操作を受け付けないというのは望ましい動作とは言えません。
しかし、今回はコンソールアプリなのでセッションが終わると非同期処理も途中で落ちてしまいます。
そこでWait()を使ってタスク完了まで待ち、完了したらセッションを閉じるようにしています。
(最初から非同期にしなければ良いと思うかもしれませんがコードに汎用性を持たせるため)

メインで呼び出すときは、次のようなコードになります。

Main.cs
using System.Threading.Tasks;

           // ファイルの保存(別タスクで非同期処理 続けて処理をおこなうときはWait()を削除する)
            Task task1 = Task.Run(() =>{  SaveFile(resultstr);  });
            task1.Wait();