C# StreamReaderを使用したCSVの読み取り
C# 忘備録です。
こちらの実装では、ストリームリーダーでCSVファイルの読み込みをし、リスト型の変数に格納します。
動作環境
Windows11 visual studio2022 .net framework4.7.2 WindowsForm
CSVファイルの読み込み用に新しいクラスを作成します。
プロジェクトファイルを右クリックし、「追加」を選び、「クラス」を選択します。
![](https://cdn-ak.f.st-hatena.com/images/fotolife/C/CEmi6653/20220901/20220901184818.png)
名前は適当に「CSVRead」にします。
![](https://cdn-ak.f.st-hatena.com/images/fotolife/C/CEmi6653/20220901/20220901185111.png)
「追加」をクリックすると「CSVRead.cs」というクラスが作成されます。
![](https://cdn-ak.f.st-hatena.com/images/fotolife/C/CEmi6653/20220901/20220901185142.png)
新しいクラスを作成したら、usingを追加します。
using System.IO;を追記するとストリームリーダが使用できるようになります。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; //追記 using System.Threading.Tasks; namespace hatenaForm { internal class CSVRead { } }
では、ストリームリーダを使用できるようになりましたので実装していきます。
まずはメソッドを追加します。
sing System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; //追記 using System.Threading.Tasks; namespace hatenaForm { internal class CSVRead { public void CsvRead01() { } } }
他のクラスから呼び出す(参照できるようにする)ため、privateではなくpublicにします。
ストリームリーダで読み込みと書いてある内容をすべて変数に入れるようにwhile文でループします。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; //追記 using System.Threading.Tasks; namespace hatenaForm { internal class CSVRead { public void CsvRead01() { //リスト型の初期化と宣言 List<string[]> str = new List<string[]>(); //CSVを読み込みモードで開く,文字種はsjis,※代表的なものでいうとUTF-8 StreamReader ls = new StreamReader(@".\Formchange.csv", Encoding.GetEncoding("sjis")); while (!ls.EndOfStream) { // CSVファイルの一行を読み込む string ln = ls.ReadLine(); // 読み込んだ一行をカンマ毎に分けて配列に格納する string[] lnvalues = ln.Split(','); //strに格納 str.Add(lnvalues); } //CSVファイルを閉じる ls.Close(); } } }
※このときのパスはデバックの実行ファイルからの相対パスで指定しています。
読み込みはこれで完了で、変数にも格納できましたが、今回は読み取りで必要な場所だけを指定します。
わたしは適当に「Formchange.csv」という適当なcsvファイルを作成しました。
![](https://cdn-ak.f.st-hatena.com/images/fotolife/C/CEmi6653/20220901/20220901191309.png)
8行目から読み込みたいため、foreach文で回しながら条件分岐で追記します。
※もっと効率が良いコードはそのへんの落ちていると思います。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; //追記 using System.Threading.Tasks; namespace hatenaForm { internal class CSVRead { List<string[]> TestItem = new List<string[]>(); public void CsvRead01() { //リスト型の初期化と宣言 List<string[]> str = new List<string[]>(); //CSVを読み込みモードで開く,文字種はsjis,※代表的なものでいうとUTF-8 StreamReader ls = new StreamReader(@".\Formchange.csv", Encoding.GetEncoding("sjis")); while (!ls.EndOfStream) { // CSVファイルの一行を読み込む string ln = ls.ReadLine(); // 読み込んだ一行をカンマ毎に分けて配列に格納する string[] lnvalues = ln.Split(','); //strに格納 str.Add(lnvalues); } //CSVファイルを閉じる ls.Close(); int c = 0; foreach (string[] l in str) { c++; //リスト[1]番目の文字数が0のとき、以降の処理がスキップする。ただしforeachは続く。 //8行目から読み込み if (l[1].Length == 0 || c <= 7) { continue; } TestItem.Add(l); } } } }
このままだと、クラスを呼び出していないため、Form1の作成されるタイミングでクラスを呼び出します。
Form1を編集します。
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace hatenaForm { public partial class Form1 : Form { //クラス型の変数を作成 //追記 CSVRead TestCSV = new CSVRead(); public Form1() { InitializeComponent(); //クラス型の変数名+クラスのメソッド名 //追記 TestCSV.CsvRead01(); } //ただ一つのフォームのインスタンスを保持するフィールド private static Form1 _instance; //ただ一つのフォームにアクセスするためのプロパティ public static Form1 Instance { get { //_instanceがnullまたは破棄されているときは、 //新しくインスタンスを作成する if (_instance == null || _instance.IsDisposed) { _instance = new Form1(); } return _instance; } } private void button1_Click(object sender, EventArgs e) { this.Visible = false; Form2 form2 = new Form2(); form2.ShowDialog(); this.Close(); } private void button2_Click(object sender, EventArgs e) { //パターン2 this.Hide(); Form3.Instance.Show(); Form5.Instance.ShowDialog(); } } }
クラス型の変数を定義し、クラス型の変数名でメソッドを呼び出します。
これで「CSVReadのCsvRead01」メソッドが動きます。
これだけだとCSVReadのCsvRead01を動かしただけなので、Form1に変数を用意し格納します。
Form1とCSVReadを編集します。
Form1.cs
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace hatenaForm { public partial class Form1 : Form { //クラス型の変数を作成 CSVRead TestCSV = new CSVRead(); //CSVReadクラスから移動 List<string[]> TestItem = new List<string[]>(); public Form1() { InitializeComponent(); //クラス型の変数名+クラスのメソッド名 //引数にリスト型変数を指定 TestCSV.CsvRead01(TestItem); } //ただ一つのフォームのインスタンスを保持するフィールド private static Form1 _instance; //ただ一つのフォームにアクセスするためのプロパティ public static Form1 Instance { get { //_instanceがnullまたは破棄されているときは、 //新しくインスタンスを作成する if (_instance == null || _instance.IsDisposed) { _instance = new Form1(); } return _instance; } } private void button1_Click(object sender, EventArgs e) { this.Visible = false; Form2 form2 = new Form2(); form2.ShowDialog(); this.Close(); } private void button2_Click(object sender, EventArgs e) { //パターン2 this.Hide(); Form3.Instance.Show(); Form5.Instance.ShowDialog(); } } }
CSVRead.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; //追記 using System.Threading.Tasks; namespace hatenaForm { internal class CSVRead { public void CsvRead01(List<string[]> TestItem) { //リスト型の初期化と宣言 List<string[]> str = new List<string[]>(); //CSVを読み込みモードで開く,文字種はsjis,※代表的なものでいうとUTF-8 StreamReader ls = new StreamReader(@".\Formchange.csv", Encoding.GetEncoding("sjis")); while (!ls.EndOfStream) { // CSVファイルの一行を読み込む string ln = ls.ReadLine(); // 読み込んだ一行をカンマ毎に分けて配列に格納する string[] lnvalues = ln.Split(','); //strに格納 str.Add(lnvalues); } //CSVファイルを閉じる ls.Close(); int c = 0; foreach (string[] l in str) { c++; //リスト[1]番目の文字数が0のとき、以降の処理がスキップする。ただしforeachは続く。 //8行目から読み込み if (l[1].Length == 0 || c <= 7) { continue; } TestItem.Add(l); } } } }
Form1にList型変数を宣言し、クラス型の変数のメソッドの引数に指定します。
Form1を読み込んだタイミングで、CSVファイルの読み込みクラスが呼び出され、List型変数に格納されました。
実装は以上になります。
またね。。。