質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

5回答

2451閲覧

CSVの情報をクラスに

YU-N

総合スコア4

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

1グッド

0クリップ

投稿2022/05/20 15:41

編集2022/05/25 06:13

プログラミング初心者です。
csvにて受け取った内容を、自作クラスでオブジェクト化したいのですが
プロパティ名が可変する場合、どのようにクラスを作ればよいのでしょうか。

複数のcsvが与えられ
各csvには下記のように情報が入っています。---

項目名1,内容,項目名2,内容,項目名3,内容・・・

例:csv1
場所,東京,取引先,株式会社A,商品,食品・・・

項目名は、決まったものではなく、どんな項目が入ってくるかわかりません。
また項目数も、ファイルによってマチマチです。

項目名の順序もマチマチという場合があります。

例:csv2
実績,あり,商品,食品,取引先,株式会社A,場所,東京,実店舗,あり・・・

これを、例えば"csv1"の”場所”の情報が欲しい時に
csv1.場所

とすれば
東京という値が取れるように
自作のクラスを使ってオブジェクト化したいのですが
具体的なコードを書くことができません。
どのような方法論が良いのか、ヒントだけでも頂けないでしょうか。

尚、”場所”や”取引先”といった項目名は、日本語で入っています。

このような場合に、クラスを使うのは適切ではないのでしょうか。

アドバイス頂ければ幸いです。

宜しくお願い致します。

<追記>
ご指摘を頂きましたので、目的を追記します。
質問の意図は私が思いついた範囲の手段であり
目的は上記にあるような形態のcsvファイルが複数供給され
それをDataGridViewに表示し、DataGridViewの編集結果を保存したい
といったことになります。

VisualStudio2022
言語はC#
WindowsForms
フレームワークは.NET Framework4.7.2
になります。

<05.25追記>
回答者様方のご親切で、当初の質問の意図そのものと少しずれ始めているにも関わらず、会話をさせて頂けております為、質問を整理させてください。

・インプットとなるcsvファイルは複数ファイルです。
・アウトプットしたいcsvファイルは1ファイル(DataGridViewに表示されているイメ―ジの通り)
・DataGridViewに表示したデータに対して、編集する場合があり、編集されたデータをアウトプットしたいです。
・DataGridViewの表示イメージを下記に示します。

イメージ説明

C#

1using System; 2using System.Collections.Generic; 3using System.Collections; 4using System.Data; 5using System.Linq; 6using System.Windows.Forms; 7 8namespace csvtest 9{ 10 public partial class Form1 : Form 11 { 12 public Form1() 13 { 14 InitializeComponent(); 15 } 16 17 private void Form1_Load(object sender, EventArgs e) 18 { 19 20 //データテーブルを作成 21 DataTable dt = new DataTable("sample"); 22 23 24 //コレクションを作成 25 var dict_col = new List<Dictionary<string, string>>(); 26 27 28 //csvデータを用意(csvの要素が配列になっているとして) 29 string[] csvdata = { "場所", "東京", "取引先", "株式会社A", "商品", "食品" }; 30 string[] csvdata2 = { "実績", "あり", "商品", "文具", "取引先", "株式会社B", "場所", "大阪", "実店舗", "あり" }; 31 32 33 34 //csvのリストを作成 35 List<string[]> csvall = new List<string[]>(); 36 37 //リストにcsvデータを追加 38 csvall.Add(csvdata); 39 csvall.Add(csvdata2); 40 41 42 43 //dictionary型に入れ込む 44 45 foreach (var a in csvall) 46 { 47 var csv_dict = new Dictionary<string, string>(); 48 49 for (int i = 0; i < a.Length; i += 2) 50 { 51 csv_dict.Add(a[i], a[i + 1]); 52 } 53 54 dict_col.Add(csv_dict); 55 56 } 57 58 //datatableのカラムにcsv_dictからキーを取り出して一通り入れる 59 60 foreach (var b in dict_col) 61 { 62 List<string> keysList = b.Keys.ToList(); //keyの一覧リストを作成して 63 foreach (string key in keysList) //データテーブルのカラムに追加していく 64 { 65 66 //データテーブルのカラムに既に存在しないか(重複)を 67 //確認。重複していた場合追加しない 68 if (0 <= Array.IndexOf(dt.Columns.list,key) //※1うまくいっていません 69 70 71 { 72 dt.Columns.Add(key); 73 74 } 75 } 76 } 77 78 //未実装:データテーブルにValueを入れていく 79 80 81 dataGridView1.DataSource = dt; 82 83 84 } 85 } 86} 87

現状困っている点
・※1 のところですが
dt.Columns.Addで例外処理(すでにkeyが存在している)が発生してしまうので
https://dobon.net/vb/dotnet/programing/arraycontains.html
こちらを参考に
重複していないときのみ、keyを追加するようにしたいのですが
using System.Data;
を記述しているのですが
DataColumnCollection
に対して、.Listがインテリセンスされません。

TN8001👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2022/05/20 22:41

目的は何ですか? CSV からカスタムクラスのオブジェクトを作りたいと言うのは手段であって目的ではないですよね。それを作って何をしたいのかの目的も書いてもらえると、別の手段 (ひょっとしたらもっと適した) の提案が出てくるかもしれません。
退会済みユーザー

退会済みユーザー

2022/05/20 22:48

何を何で作っているか書いてください。(例: Windows Forms を Visual Studio 2022 でターゲットフレームワークを .NETFramework4.8 にして作ってます・・・とか)
退会済みユーザー

退会済みユーザー

2022/05/22 00:40

質問者さん、無言ですが、回答されているのでそれらに対するフィードバックを返してください。役に立った/立たなかったぐらいはすぐに返せるのでは? 役に立たなかったならどこがダメかを書くとより期待に近い回答が出てくるかも。とにかく無言は NG です。 あと、上のコメントでお願いした質問への追記・修正の依頼への対応もやってください。
YU-N

2022/05/22 01:22

すみません。teratailの使い方もよくわかっておらず 回答以外にコメントを頂いていることに気付いておりませんでした。 返信が遅くなったこと、お詫び申し上げます。 ご指摘の通り、質問は私が思いついた範囲の手段であり 目的は質問にあるような形態のcsvファイルが複数供給され それをDataGridViewに表示し、DataGridViewの編集結果を保存したい といったことになります。 また、何で何を作っているかですが VisualStudio2022でWindowsForms フレームワークは.NET Framework4.7.2 になります。 自分で少し調べて(頂いたURLも参考にして) Datatableを作成してDataGridViewに表示させるところはできそうです。 あとは、ご教示頂いた、Dictionaryクラスに、CSVの項目と内容を入れ込んで DataGridViewで表示されるようにできれば、というところです。
退会済みユーザー

退会済みユーザー

2022/05/22 01:32

上に書かれた「目的」と「何で何を作っているか」は追加情報として質問欄に追記していただくようお願いします。ここは「質問への追記・修正の依頼」をするところですので。
退会済みユーザー

退会済みユーザー

2022/05/25 07:38 編集

今頃になって何ですがやっと質問者さんのやりたいことが分かったような気がします。 > 05.25追記 > インプットとなるcsvファイルは複数ファイルです。 それは質問に追記したコードにある、 string[] csvdata = { "場所", "東京", "取引先", "株式会社A", "商品", "食品" }; string[] csvdata2 = { "実績", "あり", "商品", "文具", "取引先", "株式会社B", "場所", "大阪", "実店舗", "あり" }; のことだと思いますが、それを CVS ファイルと言うかどうかはとりあえずちょっと置いといて、やりたいことは、 (1) その string の配列の中に「場所」「取引先」「商品」「実績」「実店舗」という文字列があれば、 (2) 配列の中の当該文字列の次の要素を抜き出して質問に貼った画像のような形で DataTable に格納し、 (3) それを DataGridView に表示し、 (4) ユーザーが DataGridView を見てその内容を編集し、 (5) 結果を CSV ファイルに書き出す。 ・・・ということで良いのですか?
YU-N

2022/05/25 10:27

SurferOnWww様 >それを CVS ファイルと言うかどうかはとりあえずちょっと置いといて すみません。便宜上このようにコードを書かせて頂きました。 >(1) その string の配列の中に「場所」「取引先」「商品」「実績」「実店舗」という文字列があれば 少し違います。 あくまでCSV(この例でいう配列)には 項目名,内容,項目名,内容,項目名,内容・・・ と連続したデータが入っているということです。 「場所」「取引先」「商品」「実績」「実店舗」と、この文字列が必ずしも決め打ちとは限らない、という想定です。 (2)~(5)まではおっしゃる通りです。
YU-N

2022/05/25 10:33

失礼しました。下にコード回答頂いておりました。確認させて頂きます。
退会済みユーザー

退会済みユーザー

2022/05/25 12:05 編集

(1) ~ (2) がかなり無理目なことをしていると思いますよ。特に、 > 「場所」「取引先」「商品」「実績」「実店舗」と、この文字列が必ずしも決め打ちとは限らない、という想定です。 というところ。決め打ちとは限らないって、誰が(何が)どうやって決めるのですか? ただ何となくテキトーにではなさそうなので、何か決める基準とかあると思いますが、そこを詳しく、ここに書いてないことは知り得ない第三者が読んで分かるように書いてください。 質問に書かれたコードははっきり言ってメチャクチャという感じで、そこはもちろん、固定であっても DataTable が作れるようになっているとは思えませんけど?
退会済みユーザー

退会済みユーザー

2022/05/25 12:24

もう一つ。 > すみません。便宜上このようにコードを書かせて頂きました。 便宜上とかで訳の分からないコードを書くのではなく、あなたの言う「複数の CVS ファイル」とは何かを、これもまた詳しく ここに書いてないことは知り得ない第三者が読んで分かるように書いてください。
YT0014

2022/05/25 12:54

対象になるCSVファイルは、何行程度なのでしょうか? また、複数行の場合、行ごとに項目名や列数が異なるのでしょうか?
退会済みユーザー

退会済みユーザー

2022/05/26 01:00

さらにもう一つ質問。 あなたの言う「CVS ファイル」の形式を以下のように見直す余地はありませんか? 場所,取引先,商品 東京,株式会社A,食品 ...他の行(もしあれば)... 実績,商品,取引先,場所,実店舗 あり,文具,株式会社B,大阪,あり ...他の行(もしあれば)...
退会済みユーザー

退会済みユーザー

2022/05/26 02:00

上の 2022/05/26 10:00 の私のコメントで書いた形(いわゆる一般的に言う CVS 形式)に見直すことができるなら、それぞれの CSV の DataTable を作ってそれを Merge メソッドで合体する方法を取ることをお勧めします。そうすれば Dictionary がどうのこうのと悩まずに簡単に DataTable が得られます。
退会済みユーザー

退会済みユーザー

2022/05/26 02:41

質問者さん、反応がないですが、「CVS ファイル」の形式を以下のように見直すということでサンプルを回答欄に追記したので見てください。 場所,取引先,商品 東京,株式会社A,食品 ...他の行(もしあれば)... 実績,商品,取引先,場所,実店舗 あり,文具,株式会社B,大阪,あり ...他の行(もしあれば)...
退会済みユーザー

退会済みユーザー

2022/05/28 02:44 編集

前にも書きましたが・・・ 質問者さん、無言ですが、追加の回答がされているのでそれらに対するフィードバックを返してください。役に立った/立たなかったぐらいはすぐに返せるのでは? 役に立たなかったならどこがダメかを書くとより期待に近い回答が出てくるかも。とにかく無言は NG です。
guest

回答5

0

ベストアンサー

項目名は、決まったものではなく、どんな項目が入ってくるかわかりません。
また項目数も、ファイルによってマチマチです。
項目名の順序もマチマチという場合があります。

普通csvって

csv

1場所,取引先,商品 2東京,株式会社A,食品 3大阪,B株式会社,飲料

こうだと思うんですけど、扱うファイルはなぜか「2個ずつ組になった1行のファイル」ということでしょうか?

単純にやるならDictionaryかなんかでいいんじゃないでしょうか。
Dictionary<TKey,TValue> クラス (System.Collections.Generic) | Microsoft Docs

どうしてもプロパティっぽく書きたいのであればExpandoObjectが使えますが、便利かどうかはわかりません。
ExpandoObject クラス (System.Dynamic) | Microsoft Docs

cs

1using System; 2using System.Collections.Generic; 3using System.Dynamic; 4using System.IO; 5using System.Linq; 6 7namespace Q8aid4d1edch6jx 8{ 9 class Program 10 { 11 static void Main() 12 { 13 File.WriteAllText("csv1.csv", "場所,東京,取引先,株式会社A,商品,食品"); 14 File.WriteAllText("csv2.csv", "実績,あり,商品,食品,取引先,株式会社A,場所,東京,実店舗,あり"); 15 16 17 var csv1 = new Dictionary<string, string>(); // 辞書(Dictionary)を作る 18 var line1 = File.ReadLines("csv1.csv").Single(); // 1行読み込む(1行でなかったらエラーFirstのほうがいいかも?) 19 var split1 = line1.Split(new char[] { ',' }); // カンマで区切る 20 for (var i = 0; i < split1.Length; i += 2) // 2個セットで使うので+=2 21 { 22 csv1.Add(split1[i], split1[i + 1]); // 2個セットの前をキー後ろを値に 23 } 24 25 Console.WriteLine(csv1["場所"]); // 東京 キーから値を取得(キーがないとKeyNotFoundException) 26 Console.WriteLine(csv1.TryGetValue("実績", out var value) ? value : "項目なし"); // 項目なし キーがあるかどうかわからない場合はTryGetValue 27 28 29 dynamic csv2 = new ExpandoObject(); 30 31 var line2 = File.ReadLines("csv2.csv").Single(); 32 var split2 = line2.Split(new char[] { ',' }); 33 for (var i = 0; i < split2.Length; i += 2) 34 { 35 var dic = (IDictionary<string, object>)csv2; // ExpandoObjectはIDictionaryにキャストできる 36 dic.Add(split2[i], split2[i + 1]); // Dictionaryと同じようにAddするとプロパティが生えてくるように見える 37 } 38 39 Console.WriteLine(csv2.場所); // 東京 プロパティのようにアクセスできるが、インテリセンスが効くわけでもないので便利かどうかはわからない 40 Console.WriteLine(csv2.実績); // あり 41 //Console.WriteLine(csv2.ほげ); // RuntimeBinderException 42 } 43 } 44}

DataGridViewがマストとなると、Datatableを選択すべきでしょう。
当初の回答とは方向性が変わりましたが、やること自体は同じような感じです(Dictionaryの代わりにDatatableになっただけ)

どうせなのでより実践的?(エンコードやまともなSplit)にしました。
CsvHelperでもなんでもいいのですが、変則csvを扱いやすかったので↓を使用しました。
NuGet Gallery | Csv 2.0.84

出番がないのはかわいそうなので、PropertyGridもついでに付けましたw
DataGridViewで複数行選択すると、PropertyGridで値を一括変更できます(なぜか単一選択と複数選択で項目の並び順が変わる。なんで??)

cs

1using System; 2using System.Collections.Generic; 3using System.ComponentModel; 4using System.Data; 5using System.Diagnostics; 6using System.IO; 7using System.Linq; 8using System.Text; 9using System.Windows.Forms; 10using Csv; 11 12namespace QQ8aid4d1edch6jx 13{ 14 public partial class Form1 : Form 15 { 16 private readonly DataTable dataTable = new DataTable(); 17 18 public Form1() 19 { 20 InitializeComponent(); 21 openFileDialog1.Filter = "CSVファイル|*.csv"; 22 dataGridView1.DataSource = dataTable; 23 dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect; 24 propertyGrid1.ToolbarVisible = false; 25 26 File.WriteAllText("csv1.csv", "場所,東京,取引先,株式会社A,商品,食品", Encoding.GetEncoding("shift_jis")); 27 File.WriteAllText("csv2.csv", "実績,あり,商品,文具,取引先,株式会社B,場所,大阪,実店舗,あり", Encoding.GetEncoding("shift_jis")); 28 } 29 30 // 変則csvの読み込み 31 private void LoadButton_Click(object sender, EventArgs e) 32 { 33 if (openFileDialog1.ShowDialog() == DialogResult.OK) 34 { 35 DataRow row = dataTable.NewRow(); 36 37 // 値にカンマや改行が含まれることも考慮しちゃんとパースする 38 string csv = File.ReadAllText(openFileDialog1.FileName, Encoding.GetEncoding("shift_jis")); 39 var options = new CsvOptions { HeaderMode = HeaderMode.HeaderAbsent, AllowNewLineInEnclosedFieldValues = true, }; 40 string[] split = CsvReader.ReadFromText(csv, options).First().Values; 41 42 // カラム数が奇数の場合はどうすべきか?(とりあえずハブったものは無視) 43 for (var i = 0; i < split.Length - 1; i += 2) 44 { 45 string key = split[i]; 46 string value = split[i + 1]; 47 48 if (!dataTable.Columns.Contains(key)) // まだ該当カラムがなければ... 49 { 50 dataTable.Columns.Add(key); // カラム追加 51 } 52 row[key] = value; 53 } 54 55 dataTable.Rows.Add(row); 56 } 57 } 58 59 // DataTableをまともなcsvに出力 60 private void SaveButton_Click(object sender, EventArgs e) 61 { 62 var header = new List<string>(); // csvヘッダー部分 63 foreach (DataColumn column in dataTable.Columns) 64 { 65 header.Add(column.Caption); // カラムヘッダーを順番に追加 66 } 67 68 var data = new List<string[]>(); // csvデータ部分(2次元配列のような状態) 69 foreach (DataRow row in dataTable.Rows) 70 { 71 var items = new List<string>(); // 1行分 72 foreach (object item in row.ItemArray) 73 { 74 items.Add(item.ToString()); // 1セル分 75 } 76 data.Add(items.ToArray()); 77 } 78 79 // ダブルクォート処理等いい感じにやってくれる 80 var csv = CsvWriter.WriteToText(header.ToArray(), data, ','); 81 82 // 上記foreachをワンライナーで書くなら 83 //var header = dataTable.Columns.Cast<DataColumn>().Select(x => x.Caption).ToArray(); 84 //var data = dataTable.Rows.Cast<DataRow>().Select(x => x.ItemArray.Select(y => y.ToString()).ToArray()); 85 //var csv = CsvWriter.WriteToText(header, data, ','); 86 87 File.WriteAllText("out.csv", csv, Encoding.GetEncoding("shift_jis")); 88 Process.Start("out.csv"); 89 } 90 91 private void DataGridView1_SelectionChanged(object sender, EventArgs e) 92 { 93 propertyGrid1.SelectedObjects = dataGridView1.SelectedRows 94 .Cast<DataGridViewRow>() 95 .Select(x => new RowWrapper((DataRowView)x.DataBoundItem)) 96 .ToArray(); 97 } 98 99 private void PropertyGrid1_PropertyValueChanged(object s, PropertyValueChangedEventArgs e) 100 { 101 dataGridView1.Refresh(); 102 } 103 } 104 105 106 // DataRowをいい感じにPropertyGridに表示する 107 // [C#/winforms: how to best bind a propertygrid and a System.Data.DataRow - Stack Overflow](https://stackoverflow.com/questions/943621/c-winforms-how-to-best-bind-a-propertygrid-and-a-system-data-datarow) 108 [TypeConverter(typeof(RowWrapperConverter))] 109 class RowWrapper 110 { 111 public List<string> Exclude { get; } = new List<string>(); 112 private readonly DataRowView rowView; 113 public RowWrapper(DataRowView rowView) => this.rowView = rowView; 114 private static DataRowView GetRowView(object component) => ((RowWrapper)component).rowView; 115 private class RowWrapperConverter : TypeConverter 116 { 117 public override bool GetPropertiesSupported(ITypeDescriptorContext context) => true; 118 public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) 119 { 120 var rw = (RowWrapper)value; 121 var props = TypeDescriptor.GetProperties(GetRowView(value), attributes); 122 var result = new List<PropertyDescriptor>(props.Count); 123 foreach (PropertyDescriptor prop in props) 124 { 125 if (rw.Exclude.Contains(prop.Name)) continue; 126 result.Add(new RowWrapperDescriptor(prop)); 127 } 128 return new PropertyDescriptorCollection(result.ToArray()); 129 } 130 } 131 private class RowWrapperDescriptor : PropertyDescriptor 132 { 133 private static Attribute[] GetAttribs(AttributeCollection value) 134 { 135 if (value == null) return null; 136 var result = new Attribute[value.Count]; 137 value.CopyTo(result, 0); 138 return result; 139 } 140 private readonly PropertyDescriptor innerProp; 141 public RowWrapperDescriptor(PropertyDescriptor innerProperty) : base(innerProperty.Name, GetAttribs(innerProperty.Attributes)) => innerProp = innerProperty; 142 public override bool ShouldSerializeValue(object component) => innerProp.ShouldSerializeValue(GetRowView(component)); 143 public override void ResetValue(object component) => innerProp.ResetValue(GetRowView(component)); 144 public override bool CanResetValue(object component) => innerProp.CanResetValue(GetRowView(component)); 145 public override void SetValue(object component, object value) => innerProp.SetValue(GetRowView(component), value); 146 public override object GetValue(object component) => innerProp.GetValue(GetRowView(component)); 147 public override Type PropertyType => innerProp.PropertyType; 148 public override Type ComponentType => typeof(RowWrapper); 149 public override bool IsReadOnly => innerProp.IsReadOnly; 150 } 151 } 152}

アプリ画像

投稿2022/05/20 23:02

編集2022/05/25 10:04
TN8001

総合スコア9321

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

YU-N

2022/05/22 00:52

仰る通り、普通はご提示頂いたようなcsv(1行目がヘッダ)なのが一般的かと思います。 実は今作りたいものが、別のシステムからcsvが供給される状況で、質問のようなcsvが提供される為困っていました。 非常に参考になりました。 dictionaryに入れ込むときに、データを整理整頓しつつ入れ込むことができるのですね。 まだ、プログラミングを始めたばかりで、書籍の情報に沿って、プログラムを書いている状況です。 (申し訳ありません。質問に書くべきでした。).NET Framework4.7.2にてコードを書いています。 .NET6などを選択すると、コードの書き方が変わってくるのでしょうか・・・。まだよくわかっていない為、.NET Frameworkで書いてしまっております。 回答ありがとうございました。 また、具体的なコードも提示頂き大変参考になりました。
TN8001

2022/05/22 01:39

> .NET Framework4.7.2にてコードを書いています。 わかりました。.NET Framework(C# 7.3)に回答を書き直しました。 どうでしょうか。まだわかりにくい点があればコメントしてください。 > .NET6などを選択すると、コードの書き方が変わってくるのでしょうか・・・。まだよくわかっていない為、.NET Frameworkで書いてしまっております。 より便利にかける場合があるといった感じでしょうか(LINQ等は慣れないと分かりにくいかもしれません) .NET Frameworkは今後更新されることはないので、.NETで問題がないのであれば.NETを選択するほうがいいとは思います。 わたしはアマチュアですし新しい機能を使ってみたいので常に最新を使っていますが、仕事ですとそうも言ってられないこともあるのでしょうね^^;
YU-N

2022/05/22 10:51

> より便利にかける場合があるといった感じでしょうか(LINQ等は慣れないと分かりにくいかもしれません) .NET Frameworkは今後更新されることはないので、.NETで問題がないのであれば.NETを選択するほうがいいとは思います。 わたしはアマチュアですし新しい機能を使ってみたいので常に最新を使っていますが、仕事ですとそうも言ってられないこともあるのでしょうね^^; 業務合理化できていないところへのアプローチなので、開発環境など、極めて自由です。趣味の範囲です。 勉強になりました。.NET6に慣れておいたほうがよさそうですね。 コードの変更ありがとうございました。 前半のDictionaryのほうを使わせて頂きたいと考えています。目では読んで、なんとなく理解できたものの 自分のコードに落とし込みたいので、恐縮ですが、しばらくお時間ください。
TN8001

2022/05/22 11:15

> 自分のコードに落とし込みたいので、恐縮ですが、しばらくお時間ください。 回答者は別に急いでおりませんので、ごゆっくりどうぞ(放置されたらイヤですが^^; データの編集・保存があるのはわかりましたが、いまいち使用法がピンときません。 > 項目名は、決まったものではなく、どんな項目が入ってくるかわかりません。 これって本当にまったく予測不能なんでしょうか? 自分の知らないところで項目が勝手に増えたり、あるいはあり得ないほどの表記ゆれとか? そうではないなら全部入りのクラス(未使用のプロパティもある)は作れそうですけど。 あるいは数パターンのクラスには分けられるとか。 例えば「実績」は必ず「あり・なし」しか入らないといった法則はないんでしょうか? あるならenumなりboolに型が決まって、編集も(不正な入力を許さないように)制限できます。 > 編集されたデータを別のクラスにオブジェクトとして渡してあげる DataTableなりDictionaryなりで渡したとして、まったく予測不能のデータでできることって限られますよね? 結局何らかのクラスに、マップすることになるんじゃないでしょうか。 例えば「商品1..商品N」をListにマップするとか、該当プロパティがなかった時だけDictionaryに入れるとかも(技術的には)可能です。 何が来るかわからないという点ではJsonなんかも似たような状況ですが、本当に予想外のデータが来たらなにもできなくないですか?^^;
退会済みユーザー

退会済みユーザー

2022/05/24 03:00 編集

横レス失礼します。 Dictionary を勧めていると理解していますが、質問にあるやりたいことの一つの、 > それをDataGridViewに表示し、DataGridViewの編集結果を保存したい はどのように実現するのでしょうか? DataGridView をユーザーが編集したあとそれを CSV に書き戻すのは Dictionary ではなかなかに大変だと思われますが、そのあたりを教えていただけると幸いです。
TN8001

2022/05/24 08:48

@SurferOnWwwさん > Dictionary を勧めていると理解しています 当初の内容 > プロパティ名が可変する場合、どのようにクラスを作ればよいのでしょうか。 に対し「Dictionaryで十分では?」という回答です。 > csv1.場所とすれば東京という値が取れるように に対しては「不可能ではないよ」というつもりでExpandoObjectも紹介しましたが、質問者には余計な情報だったかもしれません^^;(閲覧者向け情報) > DataGridView をユーザーが編集したあとそれを CSV に書き戻すのは Dictionary ではなかなかに大変だと思われます DataGridViewは後出し情報ですので「TN8001 2022/05/22 20:15」の返答を待っている状態です。 読み込んだ以上編集や保存もするだろうとは思っていましたが、PropertyGridを主に考えていました。 1行だけのDataGridViewよりは、PropertyGridのほうが見やすそうなので(現時点では複数csvを同時に出すことはないと考えています) 追加コードはかなり必要ですが、単純にコピペで編集可能なことは確認済みです。 [c# - Using a Dictionary in a propertygrid - Stack Overflow](https://stackoverflow.com/questions/1928567/using-a-dictionary-in-a-propertygrid) DataGridViewがいいと言われれば直でDataTableに入れるでしょうが、そのまま(変則的なcsvのまま)出す気はありませんでした(キーはヘッダーにして値だけ編集可能な状態にするつもりだった) キーの編集もあるのか・キーの追加削除はあるのか・キーの重複はあるのかetc. 考え出すときりがないのですが、条件よってはcsvを事前に↓のように編集する(書き出し後も逆の操作)のもお手軽かもしれませんね。 項目,値 key1,value1 key2,value2 ... keyN,valueN ぶっちゃけ(編集保存以外の)やりたいことが見えていないので、何とも言えないのですが^^;
退会済みユーザー

退会済みユーザー

2022/05/24 23:04

> DataGridViewがいいと言われれば直でDataTableに入れるでしょうが、 質問にはそのように追記されています。また、WPF ではなく Winsows Forms だそうです。 後出し情報ですが、その中の .NET Framework への変更には対応されて回答を書き直されています。 代案で WPF + PropertyGrid ということでしたら、質問者さんがそちらの方向に進む必要があることが分かるように、回答に書かれてはいかがでしょう。
TN8001

2022/05/25 00:50

>> DataGridViewがいいと言われれば直でDataTableに入れるでしょうが、 > 質問にはそのように追記されています。また、WPF ではなく Winsows Forms だそうです。 まあそうですが初心者ということでほかの選択肢を知らない可能性も高く、より良いと思える案があるなら提示します。 > 後出し情報ですが、その中の .NET Framework への変更には対応されて回答を書き直されています。 Target Frameworkは誤解や食い違いが出ようがないので取り急ぎ対応しました。 > 代案で WPF + PropertyGrid ということでしたら、質問者さんがそちらの方向に進む必要があることが分かるように、回答に書かれてはいかがでしょう。 私の回答にちらっとでもWPF要素あります?(もちろんWPFが好きなのは確かですが^^; PropertyGridが標準であるのはWinFormsですよ(WPFは標準には持っていません) [PropertyGrid クラス (System.Windows.Forms) | Microsoft Docs](https://docs.microsoft.com/ja-jp/dotnet/api/system.windows.forms.propertygrid) --- 質問は非常に一般化されて書かれていますが、実はもっと限定された状況なのではないかと思っています。 つまりクラスに回帰できるのではないかと感じているのですが、それはどうかはわかりません^^; クラスになるのと、DataTableなりDictionaryなりになるのではだいぶコードが変わってきてしまい、現時点では返答を待ちたいなという気分です。 もしこのままフェードアウトするようでも何かしらの回答に更新したいですが、どういう方向性にするか悩むところです。 データの例を見るに単に変則的なcsvの読み書きというよりは、納品伝票のようなものの集計や管理のように見えます。 > 業務合理化できていないところへのアプローチなので、開発環境など、極めて自由です。趣味の範囲です。 といったことからも場合によったらcsvの正規化?(順番の並び替えや表記ゆれの修正とか)だけC#でやって、そのあとはExcelかなんかでって手もあるのかなとも思っているのですが考えすぎですかね?
退会済みユーザー

退会済みユーザー

2022/05/25 01:12 編集

> PropertyGridが標準であるのはWinFormsですよ(WPFは標準には持っていません) 失礼しました。以下のように訂正します。 代案で Windows Forms + Dictionary + PropertyGrid ということでしたら、質問者さんがそちらの方向に進む必要があることが分かるように、回答に書かれてはいかがでしょう。 その際、編集して CSV ファイルに書き戻す(または別ファイルに書き出す)方法も書いていただくようお願いします。
退会済みユーザー

退会済みユーザー

2022/05/25 02:19 編集

何故上のコメントをしているかと言うと、私の回答へのコメントで質問者さんは、 > CSVのデータの整理整頓には、他の回答者様から頂いているdictionaryクラスを使ってみようと思います。 と述べており、TN8001 さんと YT0014 さんの回答の方向に進んでいるからです。Dictionary を使って質問にある「それをDataGridViewに表示し、DataGridViewの編集結果を保存したい」と同等なことができるのでなければそれはミスリードと言っても良いのでは?
TN8001

2022/05/25 01:48

あぁなるほど。現在質問者さんが検証中という可能性は思い当たっておりませんでした。 とりあえずの例(本当にやりたいこととは違う可能性)になってしまいますが、コードを整理して今日中には更新させていただきます^^
YU-N

2022/05/25 06:04

お二方とも、ご丁寧に返答頂き、私のレスポンスが悪いこと、質問の要件がうまくお伝えできていないこと、などから不快な思いをさせてしまっておりましたら申し訳ありません。 お二方のやりとりを100%理解できているとは考えておりませんが、私なりにやりとりをかみ砕いた上で、まず、ご質問頂いている点について回答します。 > csv1.場所とすれば東京という値が取れるように >に対しては「不可能ではないよ」というつもりでExpandoObjectも紹介しましたが、質問者には余計な情報だ>ったかもしれません^^;(閲覧者向け情報) 私の現状の能力では、Dictionary型を採用したほうが実装が早そうだったのと、「便利かどうかはわかりません。」と頂いたコメントを根拠に、選択肢から外してしまいました。 下記の回答への返答で示しております通り、現状、Dictionary型の使用は、あくまでデータの整理整頓というふうに捉えており、CSV⇒Dictionary⇒Datatableの流れで実装しようと考えております。 >編集されたデータを別のクラスにオブジェクトとして渡してあげる 申し訳ありません。やりとりの中で余計なことを申しているかもしれません。 取り急ぎ、本質問の中では csvをインプットとして、DataGridViewに表示し、アウトプットはcsv という前提でアドバイス頂ければ幸いです。 >DataTableなりDictionaryなりで渡したとして、まったく予測不能のデータでできることって限られますよね? >結局何らかのクラスに、マップすることになるんじゃないでしょうか。 質問のほうに追記で、表示したいDataGridViewを追記します。 おっしゃられていることは理解致します(作ろうとしているものの仕様を落として実現する) が、本質問においては、項目(Column)が可変 という前提条件で会話を進めさせて頂けないでしょうか。(そうしないと本末転倒な為) >読み込んだ以上編集や保存もするだろうとは思っていましたが、PropertyGridを主に考えていました。 >1行だけのDataGridViewよりは、PropertyGridのほうが見やすそうなので(現時点では複数csvを同時に出すこ>とはないと考えています) やはり私の質問において、あまりにも仕様を明確にお伝えできていないことが問題でした。 目的とするイメージを質問に追記させていただきます。 アウトプットのcsvはDataGridViewをそのまま保存したような1つのcsvで考えています。 >WPFについて お察しの通り、初学者です。ご配慮頂いているように、勉学の為、あらゆるやり方をご紹介頂くのは非常にありがたいと考えております。 しかしながら、まずはなんとか形にしてみたく、現状WindowsFormを前提に会話させて頂いてもよろしいでしょうか。 >質問は非常に一般化されて書かれていますが、実はもっと限定された状況なのではないかと思っています。 >つまりクラスに回帰できるのではないかと感じているのですが、それはどうかはわかりません^^; お察しの通り、最終的な目標物は別のシステムに出来上がったDataGridViewの表示をオブジェクト(コレクション)にして別システムのクラスに渡す という実装を目的としていますが (まずはcsv出力のところまで実装できれば、実用できる、という背景もあり) 本質問においては、改めて csvをインプットとして、DataGridViewに表示し、アウトプットはcsv という前提にさせて頂けないでしょうか。 技術要素を区分けして、クラスに回帰させる方法論について相談が必要になった際に、新しいスレッドを立てさせて頂き質問させて頂きたいと考えております。 私のつたない部分もあり、本質問の最初の意図は「動的な項目をどう処理していくか」という部分に >といったことからも場合によったらcsvの正規化?(順番の並び替えや表記ゆれの修正とか)だけC#でやって、>そのあとはExcelかなんかでって手もあるのかなとも思っているのですが考えすぎですかね? お察しの通りです。最終目標とするところまでは現状の技術力だとハードルが高いと感じている為、ワンクッション、本質問のアプリを作りたいという意図です。 返信が遅くなりましたこと、重ね重ねお詫び申し上げます。 (言い訳ですが、本業が急に忙しくなってしまい・・・) このあと、質問に追記をさせて頂きます。よろしくお願い致します。
TN8001

2022/05/25 10:04

そんなに恐縮されないで結構ですよ^^ 私たちも楽しんで回答しています(こういう機会でもないと使わないものとかもあるので) > ・インプットとなるcsvファイルは複数ファイルです。 > ・アウトプットしたいcsvファイルは1ファイル(DataGridViewに表示されているイメ―ジの通り) これを早い段階で知りたかったですw(責めているわけではありません^^ なんとなく key1,value1,key2,value2 の形は、いじってはいけないような先入観を持っていました^^;
YU-N

2022/05/30 11:27

またも返答が遅くなり申し訳ありません。 コードありがとうございます。 私が会話の中で再三言っていたDictionaryで整理してDatatableというのが 遠回りしているということにコードを提示頂いたことでやっと気づきました。 実装の予定が無かったものの PropertyGrid の定義の仕方も非常に参考になりました。 初心者でそもそもそういったものがある、という知見が無いため 選択肢にありませんでした。こういったものもあるんですね。 質問が言葉不足で、当初全然お伝えできておらず申し訳ありませんでした。 非常に好意的に対応頂いて感謝しております。 dictionaryを使えば、keyを指定することで 当初の質問にあったように、例えば「場所」という項目を取り出すことができる ということばかり考えていたのですが Datatableにおいても、カラムを指定してあげることでrowを探して、「場所」を取り出せばよいのですね。 書籍や動画などの教材を見ていても、なんとなく知識として入ってくるものの、実際に使いたいシチュエーションにならないとやはり身にはならず、私の実用に即したコードでご説明頂き、勉強になりました。 ありがとうございました。
guest

0

私はデータグリッドビューをバインドせずに使用することも多いのでバインドしないで行う方法を回答してみます。

基本的にはCSVファイルを読み込んでDictionaryでキーと値を管理してデータグリッドビューに直接設定してます。
CSV出力時もデータグリッドビューに設定されている値から直接CSV出力を行ってます。

※注意点
細かい部分は省いたり勝手に想像して作ってます。
例えばCSVの文字コードであったり、CSV出力時に空の値に対する処理であったりとか色々です。

また、バインドしない方法だと大量データを扱うような場合、データ設定時にバインドの方法に比べてパフォーマンスが悪くなります。(この辺りは共有行(sharedRow)という仕組みがデータグリッドビューにはあり、手動で行を追加する方法だと全行にアクセスするタイミングでsharedRow関連の処理が走るため。列数にもよりますが1,000行程度なら気になるほどではないと思ってます) 

イメージ説明

C#

1using System; 2using System.Collections.Generic; 3using System.Collections; 4using System.Data; 5using System.Linq; 6using System.Windows.Forms; 7using Microsoft.VisualBasic.FileIO; 8 9namespace csvtest { 10 public partial class Form1 : Form { 11 12 public Form1() { 13 InitializeComponent(); 14 15 dataGridView1.AutoGenerateColumns = false; 16 dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None; 17 dataGridView1.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.None; 18 } 19 20 private void ButtonRead_Click(object sender, EventArgs e) { 21 22 var dialog = new OpenFileDialog() { 23 Title = "CSVファイルを選択してください", 24 DefaultExt = "csv", 25 Filter = "CSVファイル|*.csv", 26 FilterIndex = 1 27 }; 28 29 if (dialog.ShowDialog(this) != DialogResult.OK) { 30 return; 31 } 32 33 var columns = new Dictionary<string, int>(); 34 var rows = new List<Dictionary<string, string>>(); 35 36 using (var parser = new TextFieldParser(dialog.FileName)) { 37 38 parser.Delimiters = new string[] { "," }; 39 40 while (true) { 41 42 if (parser.EndOfData) { 43 break; 44 } 45 46 var fields = parser.ReadFields(); 47 var row = new Dictionary<string, string>(); // CSV1行分のデータ 48 49 for (int i = 0; i < fields.Length; i += 2) { 50 51 var column = fields[i]; 52 var value = fields[i + 1]; 53 54 // 列名が存在しなかった場合は何番目に追加したかの情報とともに列一覧に追加 55 if (columns.ContainsKey(column) == false) { 56 columns.Add(column, columns.Count); 57 } 58 59 // 行の情報に値を追加 60 row.Add(column, value); 61 } 62 63 rows.Add(row); 64 } 65 66 } 67 68 DisplayCsvData(columns, rows); 69 } 70 71 private void DisplayCsvData(Dictionary<string, int> columns, List<Dictionary<string, string>> rows) { 72 73 dataGridView1.SuspendLayout(); 74 75 // 前回情報をクリア 76 dataGridView1.Rows.Clear(); 77 dataGridView1.Columns.Clear(); 78 79 // 列の作成(列の出現順で作成) 80 foreach (var csvColumn in columns.OrderBy(x => x.Value)) { 81 82 dataGridView1.Columns.Add(new DataGridViewTextBoxColumn() { 83 HeaderText = csvColumn.Key, 84 ValueType = typeof(string) 85 }); 86 87 } 88 89 // 一旦、全体の行数を作成 90 if (rows.Count > 0 || dataGridView1.AllowUserToAddRows) { 91 dataGridView1.RowCount = rows.Count + (dataGridView1.AllowUserToAddRows ? 1 : 0); 92 } 93 94 // CSVデータを設定 95 for (var i = 0; i < rows.Count; i++) { 96 97 var csvRow = rows[i]; 98 var gridRow = dataGridView1.Rows[i]; 99 100 foreach (var keyValue in csvRow) { 101 gridRow.Cells[columns[keyValue.Key]].Value = keyValue.Value; 102 } 103 104 } 105 106 // グリッドの列幅・行高さの調整とレイアウトロジックの再開 107 dataGridView1.AutoResizeColumns(); 108 dataGridView1.AutoResizeRows(); 109 dataGridView1.ResumeLayout(); 110 } 111 112 private void ButtonWrite_Click(object sender, EventArgs e) { 113 114 if (dataGridView1.RowCount == 0 || dataGridView1.ColumnCount == 0) { 115 MessageBox.Show("出力対象データがありません。"); 116 return; 117 } 118 119 // セルが編集中の場合は強制終了 120 if (dataGridView1.IsCurrentCellInEditMode) { 121 dataGridView1.EndEdit(); 122 } 123 124 var dialog = new SaveFileDialog() { 125 Title = "保存先選択", 126 DefaultExt = "csv", 127 Filter = "CSVファイル|*.csv", 128 FilterIndex = 1 129 }; 130 131 if (dialog.ShowDialog(this) != DialogResult.OK) { 132 return; 133 } 134 135 // CSV出力 136 var outputCount = 0; 137 138 using (var writer = new System.IO.StreamWriter(dialog.FileName, false)) { 139 140 foreach (DataGridViewRow gridRow in dataGridView1.Rows) { 141 142 // 追加用の行は除外 143 if (gridRow.IsNewRow) { 144 continue; 145 } 146 147 var csvRow = new List<string>(); 148 149 for (var i = 0; i < dataGridView1.ColumnCount; i++) { 150 151 var gridCell = gridRow.Cells[i]; 152 var value = gridCell.Value as string; 153 154 // 値が空の場合は出力しない 155 if (string.IsNullOrEmpty(value)) { 156 continue; 157 } 158 159 // キーと値を出力データに追加 160 csvRow.Add(gridCell.OwningColumn.HeaderText); 161 csvRow.Add(value); 162 } 163 164 if (csvRow.Count == 0) { 165 continue; 166 } 167 168 // 行を出力 169 writer.WriteLine(string.Join(",", csvRow)); 170 outputCount++; 171 } 172 173 } 174 175 if (outputCount == 0) { 176 MessageBox.Show("出力対象データがありませんでした。"); 177 return; 178 } 179 180 } 181 } 182}

投稿2022/05/28 15:31

dekaaki

総合スコア292

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

YU-N

2022/05/30 11:36

回答ありがとうございます。 コード拝読しました。 初心者につき、処理が早くなる手法といったような、そういう視点がまずなかったので、勉強になりました。 直接DataGridViewに情報を入れていけるんですね。 何らかのクラスを設けて、バインドして使うものだとばかり思っていました。 皆様、エンコードなどそのあたりも当たり前のように配慮してコードを書いている点、うまくLinqを使ってらっしゃる点(正直まだ、使い方をよく理解できていない部分で避けております・・・) 「何番目に追加したかの情報とともに」といったような配慮など 勉強になりました。 ありがとうございました。
guest

0

Dictionaryクラスが参考になるかと。
Dictionary<TKey,TValue> クラス

C#

1Dictionary<string,string> csv = new Dictionary<string,string>; 2string[] line; 3// CSVの1行を項目単位で取得する関数を作ったとして 4line= GetCsvLine(); 5for (int i=0; i<line.Count; i+=2) 6{ 7 csv.Add(line[i], line[i+1]); 8} 9 10// csv2をセットした場合、場所のデータを取得したい場合 11string locationName = csv["場所"];

これを基本に基底クラスを作成し、各々の形式用を継承クラスで作成するのが、わかりやすいかと。
*環境がないため、上記コードはコンパイルも含め未検証です。

投稿2022/05/21 15:16

YT0014

総合スコア1708

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

YU-N

2022/05/22 00:54

TN8001様の回答も含め、Dictionaryクラスが良さそうなこと、理解いたしました。 具体的なコードについても、ご教示ありがとうございます。 非常に参考になりました。
退会済みユーザー

退会済みユーザー

2022/05/24 03:00 編集

横レス失礼します。 Dictionary を勧めていると理解していますが、質問にあるやりたいことの一つの、 > それをDataGridViewに表示し、DataGridViewの編集結果を保存したい はどのように実現するのでしょうか? DataGridView をユーザーが編集したあとそれを CSV に書き戻すのは Dictionary ではなかなかに大変だと思われますが、そのあたりを教えていただけると幸いです。
YT0014

2022/05/24 03:59

SurferOnWwwさんへ。 概念の理解しやすいDictionary を持つクラスの作成を勧めているつもりなのですが、説明が拙いようで申し訳ありません。 また、他の回答へのYU-Nさんの反応が薄かったため、かみ砕いた説明が必要に思われたための投稿です。 その為、書出しに関しては考慮しておりません。 CSVの項目が固定順なら、専用クラスにキーリストを持ち、CSVクラスにそのキーリストを使って書き出すことで実現できそうです。もし、戻し側も順不同で良いのなら、キーリストも不要ですね。 もしも、完全な解決策なのか?という趣旨のご質問でしたら、「No」ですね。 不完全な回答をするなと言われれば、仰る通りですごめんなさい、としか、返せませんね。
YT0014

2022/05/29 09:51

SurferOnWwwさんへ。 当方の回答コメントに対して、何の御反応も頂戴しておりませんが、何が落ち度がございましたでしょうか?ご多忙中とは存じますが、追記修正依頼にはご投稿されておられますので、ご納得いただけたのか否かくらいは、ご対応可能かと思われますが、御反応頂くにも値しないような内容でしたでしょうか?
退会済みユーザー

退会済みユーザー

2022/05/30 11:50

返事が遅れてすみません。2022/05/24 12:59 のコメントで説明いただいたことで納得しております。
guest

0

CSV からカスタムクラスのオブジェクトを作りたいと言うのは手段であって目的ではなく、目的は CSV ファイルの内容をユーザーに表示しユーザーがそれを編集して編集結果を CSV ファイルに書き出すというようなことではなかろうかと想像してます。

その想像が当たっていれば、CSV ファイルから DataTabe を作成し、それを Windows Forms アプリの DataGridView にバインドして表示してはいかがですか?

ユーザーが DataGridView を操作して編集した結果は自動的に DataTable に反映されるので、DataTable からデータを読んで CSV ファイルに書き出すこともできます。

具体例は以下の記事を見てください。

CSV ファイルを DataGridView に表示
http://surferonwww.info/BlogEngine/post/2020/09/11/show-date-in-csv-file-on-datagridview.aspx

紹介した記事には TextFieldParser を使う案と ADO.NET + OelDb + JET を使う案が書いてありますが、CSV ファイルの列が不定ということであれば前者のコードが使えると思います。


【追記】

質問者さんの言う「CVS ファイル」の形式を以下のように(いわゆる一般的に言う CVS 形式に)見直す余地はありませんか?

場所,取引先,商品
東京,株式会社A,食品
...他の行(もしあれば)...

実績,商品,取引先,場所,実店舗
あり,文具,株式会社B,大阪,あり
...他の行(もしあれば)...

上の形にすることができるなら、それぞれの CSV の DataTable を作ってそれを Merge メソッドで合体する方法を取ることをお勧めします。そうすれば Dictionary がどうのこうのと悩まずに簡単に DataTable が得られます。

サンプルを載せておきます。

CSV ファイルは以下の通り。(質問者さんのサンプルに一行追加)

イメージ説明

イメージ説明

コードは以下の通り。先に紹介した記事とほぼ同じです。違うのは 2 つの CSV ファイルから 2 つの DataTable を作って、それを Merge してから DataDridView に表示しているところです。

C#

1using System; 2using System.ComponentModel; 3using System.Data; 4using System.Text; 5using System.Windows.Forms; 6using Microsoft.VisualBasic.FileIO; 7 8namespace WindowsFormsApp1 9{ 10 public partial class Form4 : Form 11 { 12 private BindingSource bindingSource1; 13 private DataTable table; 14 15 public Form4() 16 { 17 InitializeComponent(); 18 19 this.components = new Container(); 20 this.bindingSource1 = 21 new BindingSource(this.components); 22 this.dataGridView1.DataSource = this.bindingSource1; 23 } 24 25 private void Form4_Load(object sender, EventArgs e) 26 { 27 // CVS ファイルのパス 28 string path1 = @"C:\Users...\CsvData1.csv"; 29 string path2 = @"C:\Users...\csvData2.csv"; 30 31 // CSV ファイルを読む際の文字エンコーディングを指定 32 Encoding encoding = new UTF8Encoding(); 33 34 this.table = CreateDataTable(path1, encoding); 35 DataTable table2 = CreateDataTable(path2, encoding); 36 37 this.table.Merge(table2); 38 this.table.AcceptChanges(); 39 40 this.bindingSource1.DataSource = this.table; 41 } 42 43 // ================ 以下ヘルパメソッド ================ 44 45 // TextFieldParser 版 46 // 指定されたパスから CSV ファイルを読んできて DataTable 47 // を作成。CSV ファイルのカラム数とその型は不定という前提 48 // なので、全カラムを string 型として扱わざるを得ない。 49 // TextFieldParser は CSV ファイルに BOM が付与されていれ 50 // ばそれからエンコーディングを自動判別。BOM 無しの場合は 51 // 引数の encoding の指定に従う 52 protected DataTable CreateDataTable(string path, 53 Encoding encoding) 54 { 55 // TextFieldParser は Microsoft が提供している Visual 56 // Basic .NET 用のクラスライブラリ。C# のアプリでも 57 // Microsoft.VisualBasic.dll を参照に追加すれば利用可 58 using (TextFieldParser tfp = 59 new TextFieldParser(path, encoding)) 60 { 61 //フィールドがデリミタで区切られている 62 tfp.TextFieldType = FieldType.Delimited; 63 64 // デリミタを , とする 65 tfp.Delimiters = new string[] { "," }; 66 67 // フィールドを " で囲み、フィールド内に改行文字、 68 // デリミタを含めることができるか 69 tfp.HasFieldsEnclosedInQuotes = true; 70 71 // 空白文字をトリム 72 tfp.TrimWhiteSpace = true; 73 74 // CSV ファイルは 1 行目がヘッダであることが条件 75 string[] headers = tfp.ReadFields(); 76 int fieldCount = headers.Length; 77 78 DataTable dt = new DataTable(); 79 DataRow dr; 80 DataColumn dc; 81 82 // DataTable の列の設定 83 for (int i = 0; i < fieldCount; i++) 84 { 85 dc = new DataColumn(headers[i], typeof(String)); 86 dt.Columns.Add(dc); 87 } 88 89 // CSV のデータから DataRow を作り DataTable 90 // に追加していく 91 while (!tfp.EndOfData) 92 { 93 string[] fields = tfp.ReadFields(); 94 95 dr = dt.NewRow(); 96 for (int i = 0; i < fieldCount; i++) 97 { 98 dr[headers[i]] = fields[i]; 99 } 100 dt.Rows.Add(dr); 101 } 102 103 return dt; 104 } 105 } 106 } 107}

結果は以下のようになります。

イメージ説明

投稿2022/05/21 00:31

編集2022/05/26 02:28
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

YU-N

2022/05/22 00:41

返信が遅くなり申し訳りません。 ご教示頂いたDataTableとDataGridViewについて ご紹介頂いたURLも参考にしつつ、自分なりに他のWEB上の情報も調べ コードを試していました。 CSVのデータの整理整頓には、他の回答者様から頂いているdictionaryクラスを使ってみようと思います。 非常に参考になりました。ありがとうございます。
YU-N

2022/05/22 01:07

連投すみません。 読み返していて言葉不足でした。 ご指摘の通り、用途はDataGridVeiwに表示して~ 編集されたデータを別のクラスにオブジェクトとして渡してあげる というのが目的で 仰る通り、質問の主旨はあくまで手段でした。 自作クラスを使おうと思ったのは 使っている教材の中で、自作クラスをデータバインドしてDataGridViewに表示する手順が示されていた為で DataTableの存在を知らかったためです。
退会済みユーザー

退会済みユーザー

2022/05/22 01:38

> CSVのデータの整理整頓には、他の回答者様から頂いているdictionaryクラスを使ってみようと思います。 DataGridView に表示するだけなら Dictionary でもよいと思います。DataTable / Dictionary どちらがやりやすいか、どちらが保守しやすいかで決めれば良いと思います。 しかし、もしユーザーが DataGridView を編集して編集結果を CSV ファイルに書き出すことまで行うなら、DataTable の一択です。今は詳しくは書きませんが、興味があれば聞いてもらえれば答えます。
YU-N

2022/05/22 11:05

いろいろとご教示ありがとうございます。 >しかし、もしユーザーが DataGridView を編集して編集結果を CSV ファイルに書き出すことまで行うなら、DataTable の一択です。 編集結果をCSVに書き出したいので、最終的にDataTableに値を入れて 使ったほうが良さそうですね。 うまく理解がまとまっていないのですが 他の方々からもご提案頂いているDictionary型は データを整理するための手段だと捉えておりました。 (申し訳ありません。本業のスキマ時間で考えているという状況で、自分のコードを書いて読んでもらうべきかと思いますがなかなかコードに落とし込めておらず・・・) ①CSV⇒Dictionary⇒Datatable という形でデータを渡そうと思っておりました。 Dictionaryに移せば、全てのkeyをDatatableに渡すことで 動的にカラムを変更できるかな?と思っておりました。 最初に質問した通り、項目が動的で、順不定なのですが CSV⇒Datatableでも書けそうでしょうか。(頭が悪くうまく思いつかず・・・) ②Dictionary型でも直接DataGridViewに表示(バインド?)することはできるのでしょうか? >今は詳しくは書きませんが、興味があれば聞いてもらえれば答えます。 お手数ですが、そのあたりもお手すきの際に、ご教示頂けると助かります。 宜しくお願い致します。
退会済みユーザー

退会済みユーザー

2022/05/22 11:43

以下の記事の「非接続型のデータ更新」のセクションの図1を見てください。文章は読まなくてもいいので図だけ見てください。 DB 設計者のための明解 ADO.NET 第 1 回 https://docs.microsoft.com/ja-jp/previous-versions/cc482903%28v=msdn.10%29 ユーザーが DataGridView を操作(行の削除・追加・訂正)した結果は図1にあるように DataTable に反映されます。ユーザーの編集操作が終わったら図1の編集結果で一気に CSV ファイルを生成できます。DataTable を使ってそういうアプリが簡単に作れるようにできているのです。
YU-N

2022/05/30 11:31

返信が遅れて申し訳ありません。 csvの形式については、検討すべきところとは考えるものの 別のシステムからアウトプットされるものでコントロール外なので、今回の質問の要件定義としては、やはり動的にカラムを設定していく、という前提とさせて頂きました。 Datatableはマージできるんですね。 csvごとにdatatableに落とし込めれば、マージしていくこともできそうですね。 勉強になりました。ありがとうございました。
guest

0

項目名が不定だとクラスを動的に生成することになります。
参考になりそうな記事を紹介しますが、はっきり言って無理筋じゃないでしょうか。
「クラスの動的生成」
https://horiuchi.hateblo.jp/entry/20081109/1226214664

DataTable に格納するのが現実的かなと思います。
「基本 CSVファイルをDataTableに読み込んで表示する」
https://www.oborodukiyo.info/Forms/VS2008/F-ReadCSVToDataTable

投稿2022/05/20 16:49

KOZ6.0

総合スコア2626

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

YU-N

2022/05/21 12:22

回答ありがとうございます。 URL先拝見しました。 クラスの動的生成は今の私の能力では難しそうです。 DataTable検討してみます。ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問