teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

3

追記その2

2019/06/27 03:22

投稿

退会済みユーザー
answer CHANGED
@@ -100,4 +100,107 @@
100
100
 
101
101
  Schema.ini の型指定を例えば Text を Long にするなど変換できない様に変えれば何らかのエラーが出ると思っていたのですが、出ませんでした。(ただし、DataGridView への表示結果は期待したものにはなりませんが)
102
102
 
103
- **【注】ただし C# のオブジェクトとして取得した結果の型は schema.ini で指定した通りになります。上のコード例では DataTable に CSV データを取得していますが、DataTable の型は DataGridView の左から順に int, string, decimal, bool になります。そこはこのコードのメリットと言えるのではないでしょうか。**
103
+ **【注】ただし C# のオブジェクトとして取得した結果の型は schema.ini で指定した通りになります。上のコード例では DataTable に CSV データを取得していますが、DataTable の型は DataGridView の左から順に int, string, decimal, bool になります。そこはこのコードのメリットと言えるのではないでしょうか。**
104
+
105
+ **【追記2】**
106
+
107
+ 下の 2019/06/27 12:03 の私のコメントで
108
+
109
+ > hihijiji さんの案 CsvHelper を NuGet でインストールして使うのが正解のようです。CSV ファイルの特定の列だけ取得できますし、指定した型に変換できないと例外をスローしてくれます。後で例を回答欄に追記しておきます。
110
+
111
+ と書きましたが、上の【追記】と同じ CSV ファイルの同じ列を CsvHelper で取得し、同じ Form の同じ DataGridView に表示した例を以下に書いておきます。
112
+
113
+ ただし、質問者さんの扱う CSV ファイルにはヘッダがないそうですが、下の例ではヘッダありにしています。ヘッダなしでも対応できるかどうかまでは調べてません。
114
+
115
+ コードは以下の通りです。上のコードに Product, ProductMapper クラスを追加し、Form12_Load ハンドラでは先の ADO.NET のコードをコメントアウトして CsvHelper のコードを追記しただけです。
116
+
117
+ ```
118
+ using System;
119
+ using System.Collections.Generic;
120
+ using System.ComponentModel;
121
+ using System.Data;
122
+ using System.Drawing;
123
+ using System.Linq;
124
+ using System.Text;
125
+ using System.Threading.Tasks;
126
+ using System.Windows.Forms;
127
+ using System.Data.OleDb;
128
+ using CsvHelper;
129
+ using CsvHelper.Configuration;
130
+ using System.IO;
131
+
132
+ namespace WindowsFormsApplication1
133
+ {
134
+ public partial class Form12 : Form
135
+ {
136
+ private DataGridView dataGridView1;
137
+ private BindingSource bindingSource1;
138
+ private string path = @"C:\Users\surfe...\WindowsFormsApplication1\";
139
+ private string filename = "Products.csv";
140
+
141
+ public Form12()
142
+ {
143
+ InitializeComponent();
144
+
145
+ this.dataGridView1 = new DataGridView();
146
+ this.dataGridView1.Dock = System.Windows.Forms.DockStyle.Fill;
147
+ this.bindingSource1 = new BindingSource();
148
+ this.dataGridView1.DataSource = this.bindingSource1;
149
+ this.Controls.Add(this.dataGridView1);
150
+ }
151
+
152
+ private void Form12_Load(object sender, EventArgs e)
153
+ {
154
+ // 接続文字列。HDR=Yes で一行目をヘッダーとして扱う
155
+ //string conString =
156
+ // "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" +
157
+ // this.path +
158
+ // ";Extended Properties=\"text;HDR=Yes;FMT=Delimited\"";
159
+
160
+ //OleDbConnection con = new OleDbConnection(conString);
161
+ //string commText = "SELECT [ProductID],[ProductName],[UnitPrice],[Discontinued] FROM [" + this.filename + "]";
162
+ //OleDbDataAdapter da = new OleDbDataAdapter(commText, con);
163
+
164
+ //DataTable dt = new DataTable();
165
+ //da.Fill(dt);
166
+
167
+ //this.bindingSource1.DataSource = dt;
168
+
169
+ using (var csv = new CsvReader(new StreamReader(this.path + this.filename)))
170
+ {
171
+ var config = csv.Configuration;
172
+ config.HasHeaderRecord = true; // ヘッダーが存在する場合 true
173
+ config.RegisterClassMap<ProductMapper>();
174
+ var list = csv.GetRecords<Product>();
175
+ this.bindingSource1.DataSource = list;
176
+ }
177
+ }
178
+ }
179
+
180
+ public class Product
181
+ {
182
+ public int ProductID { get; set; }
183
+ public string ProductName { set; get; }
184
+ public decimal UnitPrice { set; get; }
185
+ public bool Discontinued { set; get; }
186
+ }
187
+
188
+ public class ProductMapper : ClassMap<Product>
189
+ {
190
+ private ProductMapper()
191
+ {
192
+ Map(c => c.ProductID).Index(0);
193
+ Map(c => c.ProductName).Index(1);
194
+ Map(c => c.UnitPrice).Index(5);
195
+ Map(c => c.Discontinued).Index(9);
196
+ }
197
+ }
198
+ }
199
+
200
+ ```
201
+
202
+ 結果は上の画像と同じです。
203
+
204
+ クラス Product で指定した型に変換できないと例外がスローされます。例えば int 型でなければならない ProductID を CSV ファイルで "xxxxx" にすると以下の例外がスローされます。
205
+
206
+ ![イメージ説明](e5ecb4f556158230c6704cbd1d28e285.jpeg)

2

追記

2019/06/27 03:22

投稿

退会済みユーザー
answer CHANGED
@@ -98,4 +98,6 @@
98
98
 
99
99
  ![イメージ説明](3b00e846e3c535fc8c4b9affab98994b.jpeg)
100
100
 
101
- Schema.ini の型指定を例えば Text を Long にするなど変換できない様に変えれば何らかのエラーが出ると思っていたのですが、出ませんでした。(ただし、DataGridView への表示結果は期待したものにはなりませんが)
101
+ Schema.ini の型指定を例えば Text を Long にするなど変換できない様に変えれば何らかのエラーが出ると思っていたのですが、出ませんでした。(ただし、DataGridView への表示結果は期待したものにはなりませんが)
102
+
103
+ **【注】ただし C# のオブジェクトとして取得した結果の型は schema.ini で指定した通りになります。上のコード例では DataTable に CSV データを取得していますが、DataTable の型は DataGridView の左から順に int, string, decimal, bool になります。そこはこのコードのメリットと言えるのではないでしょうか。**

1

追記

2019/06/26 06:36

投稿

退会済みユーザー
answer CHANGED
@@ -2,4 +2,100 @@
2
2
 
3
3
  135 列ある CSV ファイルの中から特定の 5 列のデータのみ取得したい。その際、各列の型を判定してそれを C# のオブジェクトに反映したいということですか?
4
4
 
5
- であれば、JET または ACE プロバイダ + ADO.NET を使って、型は schema.ini というファイルを作って指定するという方向で考えるというのはいかがですか?
5
+ であれば、JET または ACE プロバイダ + ADO.NET を使って、型は schema.ini というファイルを作って指定するという方向で考えるというのはいかがですか?
6
+
7
+ **【追記】**
8
+
9
+ 検証してみましたが、JET または ACE プロバイダ + ADO.NET で特定の列を取得するのは SELECT クエリで取得したい列を指定すれば可能でしたが、schema.ini ファイルに指定される型と CSV データが違ってもエラーは出ませんでした。
10
+
11
+ なので、質問者さんの目的、
12
+
13
+ > エラーメッセージが出るようにしたいです。
14
+
15
+ には上記の案ではダメでした。すみません。
16
+
17
+
18
+ 以下、お役には立たないと思いますが、ご参考までにどのように検証したかを書いておきます。
19
+
20
+ まず、CSV ファイルですが、Microsoft のサンプルデータベース Northwind の Products テーブルから SSMS を使ってエクスポートしたものを使います。
21
+
22
+ ![イメージ説明](4071879e0de9cdb9621ee5062dda0941.jpeg)
23
+
24
+ Schema.ini は以下の通り。
25
+
26
+ ```
27
+ [Products.csv]
28
+ ColNameHeader=True
29
+ Format=CSVDelimited
30
+ CharacterSet=65001
31
+ Col1=ProductID Long
32
+ Col2=ProductName Text
33
+ Col3=SupplierID Long
34
+ Col4=CategoryID Long
35
+ Col5=QuantityPerUnit Text
36
+ Col6=UnitPrice Currency
37
+ Col7=UnitsInStock Short
38
+ Col8=UnitsOnOrder Short
39
+ Col9=ReorderLevel Short
40
+ Col10=Discontinued Bit
41
+ ```
42
+ Windows Forms アプリのコードは以下の通り。
43
+
44
+ ```
45
+ using System;
46
+ using System.Collections.Generic;
47
+ using System.ComponentModel;
48
+ using System.Data;
49
+ using System.Drawing;
50
+ using System.Linq;
51
+ using System.Text;
52
+ using System.Threading.Tasks;
53
+ using System.Windows.Forms;
54
+ using System.Data.OleDb;
55
+
56
+ namespace WindowsFormsApplication1
57
+ {
58
+ public partial class Form12 : Form
59
+ {
60
+ private DataGridView dataGridView1;
61
+ private BindingSource bindingSource1;
62
+ private string path = @"C:\Users...\WindowsFormsApplication1\";
63
+ private string filename = "Products.csv";
64
+
65
+ public Form12()
66
+ {
67
+ InitializeComponent();
68
+
69
+ this.dataGridView1 = new DataGridView();
70
+ this.dataGridView1.Dock = System.Windows.Forms.DockStyle.Fill;
71
+ this.bindingSource1 = new BindingSource();
72
+ this.dataGridView1.DataSource = this.bindingSource1;
73
+ this.Controls.Add(this.dataGridView1);
74
+ }
75
+
76
+ private void Form12_Load(object sender, EventArgs e)
77
+ {
78
+ // 接続文字列。HDR=Yes で一行目をヘッダーとして扱う
79
+ string conString =
80
+ "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" +
81
+ this.path +
82
+ ";Extended Properties=\"text;HDR=Yes;FMT=Delimited\"";
83
+
84
+ OleDbConnection con = new OleDbConnection(conString);
85
+ string commText = "SELECT [ProductID],[ProductName],[UnitPrice],[Discontinued] FROM [" + this.filename + "]";
86
+ OleDbDataAdapter da = new OleDbDataAdapter(commText, con);
87
+
88
+ DataTable dt = new DataTable();
89
+ da.Fill(dt);
90
+
91
+ this.bindingSource1.DataSource = dt;
92
+ }
93
+ }
94
+ }
95
+ ```
96
+
97
+ 結果は以下のようになります。
98
+
99
+ ![イメージ説明](3b00e846e3c535fc8c4b9affab98994b.jpeg)
100
+
101
+ Schema.ini の型指定を例えば Text を Long にするなど変換できない様に変えれば何らかのエラーが出ると思っていたのですが、出ませんでした。(ただし、DataGridView への表示結果は期待したものにはなりませんが)