【解答】C# (dotnetcore) CSVファイルを永続化に利用したコンソールアプリの作成
本エントリは、以下のエントリに対する解答の1つです。
解答(ソース)
以下が回答となります。このプログラムには、改善ポイント(課題)があります。
using System; using System.Collections.Generic; namespace csvExample { class Program { //メモリ上の住所録データ private static List<string[]> Rows = new List<string[]>(); //CSVファイルのパス private const string CSV_PATH = @"data.csv"; static void Main(string[] args) { //CSVファイルを読み込む ReadCsv(); while (true) { //コマンドの一覧を表示 Console.WriteLine("Command:list or add or init or exit"); //コマンドの入力を求める string command = Console.ReadLine(); if(command == "list") { //一覧表示の場合 foreach(var row in Rows) { //メモリ上の内容を表示 Console.Write("name:["); Console.Write(row[0]); Console.Write("] telno:["); Console.Write(row[1]); Console.WriteLine("]"); } } else if(command == "add") { //追加の場合 //追加する内容の読み込み Console.WriteLine("name?"); string name = Console.ReadLine(); Console.WriteLine("telno?"); string telno = Console.ReadLine(); //メモリに追加 Rows.Add(new string[] { name, telno }); //ファイルに書き込む WriteCsv(); } else if(command == "init") { //初期化の場合 if (System.IO.File.Exists(CSV_PATH)) { System.IO.File.Delete(CSV_PATH); Rows = new List<string[]>(); } } else if (command == "exit") { //終了の場合 break; } } } //CSV書き込み static void WriteCsv() { //ファイルを書き込む using (var writer = new System.IO.StreamWriter(CSV_PATH)) { //現在の内容を回す foreach (var row in Rows) { //1行ずつ書き込む(項目をカンマ区切りでつなげる) writer.WriteLine(String.Join(",", row)); } } } //CSV読み込み static void ReadCsv() { //ファイルが無い場合は何もしない if (!System.IO.File.Exists(CSV_PATH)) return; //ファイルがある場合、読み込む using (var reader = new System.IO.StreamReader(CSV_PATH)) { //1行ずつ読み込む string line; while((line = reader.ReadLine()) != null) { //カンマ区切りを分解 Rows.Add(line.Split(",")); } } } } }
各項目の解説
ここでの項目は、プロパティやメソッドのことを表しています。 それぞれ、以下のような役割があります。
項目 | 説明 |
---|---|
Rows | CSVから読み込んだデータを保持する領域。データを追加した場合、ここに追加される |
CSV_PATH | CSVファイルのパス |
Main | プログラムのエントリポイント。 初期処理で、ReadCSVを実行し、 その後はlist、add、init、exitのコマンドを受け付け、各コマンドに合わせた処理を行っている |
WriteCsv | Rowsの内容をCSVファイルに保存する関数 |
ReadCsv | CSVファイルを読み込み、内容をRowsに設定する関数 |
プログラム上の課題
カンマを含められない
nameや、telnoにカンマを含められません。 このプログラムでカンマを入力することは想定されていませんが、 できれば、CSVの標準的な保存、読み込みとしたいところです。
Main関数の行数が多い
もう少し分割したいところですね。
コマンド毎に関数に分けるっていうアプローチが良さそうですね。
Dictionary<string, Action >というアプローチもありかもしれません。
ファイルの行数に伴いレスポンスが悪化する
保存する毎に、ファイルを作り直しているため、レコード数が増えると遅くなっていく設計となっている。
追加しか行わないなら、追記というアプローチを行うべき。
ファイルの場合、固定長とすることで、部分編集、レコードの削除等も高速にできそう。
今風の作りにする場合は、データベースを利用するという事になる。
この場合はSQLiteが良さそう。
RDBMSが今風というのは少し違う気もするが・・・
BerkeleyDBとか・・・
発展のアプローチ
本プログラムの発展を考えたアプローチとして、以下のようなことができれば便利そう。
コマンドライン引数を使った操作ができれば便利かもしれない
コマンドライン引数で、list、add、initを操作できれば、以下のように、パイプやリダイレクトを利用した、他プログラムとの連携も可能となる。
dotnet csvExample.dll list > data.txt