前回の記事とは逆にDataTableの内容をCSVへ出力します。
今回もDataTableの拡張メソッドとして書式を以下のようにします。
public static void ToCsv(this DataTable dt, string filePath, bool hasHeader, Encoding encoding)
第1引数はCSVへ出力するDataTableで、拡張メソッドとするために this をつけます。
第2引数はCSVファイルのパスです。
第3引数はCSVファイルの1行目をヘッダと見なすか判断するためのフラグで、trueなら1行目をヘッダと見なしてDataTableの列名を出力します。
第4引数はCSVファイルのエンコードを指定します。
各項目はダブルクォートで括ります。
今回もDataTableの拡張メソッドとして書式を以下のようにします。
public static void ToCsv(this DataTable dt, string filePath, bool hasHeader, Encoding encoding)
第1引数はCSVへ出力するDataTableで、拡張メソッドとするために this をつけます。
第2引数はCSVファイルのパスです。
第3引数はCSVファイルの1行目をヘッダと見なすか判断するためのフラグで、trueなら1行目をヘッダと見なしてDataTableの列名を出力します。
第4引数はCSVファイルのエンコードを指定します。
各項目はダブルクォートで括ります。
public static void ToCsv(this DataTable dt, string filePath, bool hasHeader, Encoding encoding)
{
using ( TextWriter writer = new StreamWriter(filePath, false, encoding))
{
// ヘッダが必要ならDataTableの列名を1行目に出力する
if (hasHeader)
{
string header = string.Empty;
// 列名を取得してカンマ区切りにする(最後のカンマを削除)
foreach (DataColumn column in dt.Columns)
{
header = string.Format("\"{0}\",", column.ColumnName);
}
header = header.Remove(header.Length - 1);
writer.WriteLine(header);
}
// データを展開
foreach (DataRow row in dt.Rows)
{
string line = string.Empty;
// 各行データを取得してカンマ区切りにする(最後のカンマを削除)
foreach (object column in row.ItemArray)
{
line = string.Format("\"{0}\",", column);
}
line = line.Remove(line.Length - 1);
writer.WriteLine(line);
}
}
}
スポンサーサイト
CSVファイルを読み込みDataTableに展開します。
CSVファイルはカンマで区切られた複数の項目が1行に存在する、
複数行で構成されたデータ構造であるため、
カンマ区切りの各項目を"列"を見なすした、テーブル構造になります。
テーブル構造ならば、そのままDataTableに展開可能であるため、
CSVファイルを読み込んで、DataTableに落とし込むコードを考えてみます。
今回はCSVファイルの読み込みに、Microsoft.VisualBasic.FileIO.TextFieldParserをします。
さらにDataTableの拡張メソッドとして書式を以下のようにします。
public static void FromCsv(this DataTable dt, string filePath, bool hasHeader, Encoding encoding)
第1引数はCSVから読み込んだ内容を展開するDataTableで、拡張メソッドとするために this をつけます。
第2引数はCSVファイルのパスです。
第3引数はCSVファイルの1行目をヘッダと見なすか判断するためのフラグで、trueなら1行目をヘッダと見なしてヘッダ名をそのままDataTableの列名にします。
falseならヘッダなしと見なしてDataTableの列名を "Column1、Column2、Column3・・・ColumnN" とします。
第4引数はCSVファイルのエンコードを指定します。
尚、各列の型は string とします。
CSVファイルはカンマで区切られた複数の項目が1行に存在する、
複数行で構成されたデータ構造であるため、
カンマ区切りの各項目を"列"を見なすした、テーブル構造になります。
テーブル構造ならば、そのままDataTableに展開可能であるため、
CSVファイルを読み込んで、DataTableに落とし込むコードを考えてみます。
今回はCSVファイルの読み込みに、Microsoft.VisualBasic.FileIO.TextFieldParserをします。
さらにDataTableの拡張メソッドとして書式を以下のようにします。
public static void FromCsv(this DataTable dt, string filePath, bool hasHeader, Encoding encoding)
第1引数はCSVから読み込んだ内容を展開するDataTableで、拡張メソッドとするために this をつけます。
第2引数はCSVファイルのパスです。
第3引数はCSVファイルの1行目をヘッダと見なすか判断するためのフラグで、trueなら1行目をヘッダと見なしてヘッダ名をそのままDataTableの列名にします。
falseならヘッダなしと見なしてDataTableの列名を "Column1、Column2、Column3・・・ColumnN" とします。
第4引数はCSVファイルのエンコードを指定します。
尚、各列の型は string とします。
public static void FromCsv(this DataTable dt, string filePath, bool hasHeader, Encoding encoding)
{
// CSVファイルが存在するかチェック
if (!System.IO.File.Exists(filePath)) { throw new System.IO.FileNotFoundException(filePath); }
// DataTableを事前にクリア
dt.Clear();
using (TextFieldParser parser = new TextFieldParser(filePath, encoding))
{
// 区切り形式指定
parser.TextFieldType = FieldType.Delimited;
// ","区切り
parser.SetDelimiters(new string[] { "," });
// ダブルクォート許容
parser.HasFieldsEnclosedInQuotes = true;
// 空白トリム無効
parser.TrimWhiteSpace = false;
// 1行目を基準に列作成
if (!parser.EndOfData)
{
// フィールド区切りで1行読み込み
string[] fields = parser.ReadFields();
// フィールド分のカラム作成
DataColumn[] columns = new DataColumn[fields.Length];
// 列作成
for (int i = 0; i < columns.Length; ++i)
{
string columnName = hasHeader ? fields[i] : "Column" + i;
columns[i] = new DataColumn(columnName, typeof(string));
}
dt.Columns.AddRange(columns);
// ヘッダが存在しない場合のみ1行目もデータとしてDataTableに展開
if (!hasHeader)
{
DataRow row = dt.NewRow();
row.ItemArray = fields;
dt.Rows.Add(row);
}
}
// 残りファイル終端まで読み込み
while (!parser.EndOfData)
{
// フィールド区切りで1行読み込み
string[] fields = parser.ReadFields();
// 行追加
DataRow row = dt.NewRow();
row.ItemArray = fields;
dt.Rows.Add(row);
}
}
}
C#のプロジェクトへ型付きDataSetを追加し、定義したDataTableへXMLファイルを読み込みます。
読み込むXMLファイルは以下の通り。

XMLファイルには家電に関する情報を格納し、「炊飯器」、「冷蔵庫」、「レンジ」の簡単な仕様を定義します。
「炊飯器」、「冷蔵庫」、「レンジ」は各々1つのテーブルを表すことになります。
例えば、炊飯器には「メーカー」、「省エネ基準達成率」、「年間電気代」、「重さ」の列が存在し、3つの行が定義されている状態で、DataSetはDataTableの集合を持つため、これが1つのDataTableと関連付くことになります。
DataTableとの関連付けは該当するXML内のタグ名と、DataTableのテーブル名及び列名を同じにすることで自動で行われます。
では、実践してみましょう。
Visual Studioで新規のWindowsフォームアプリケーションのプロジェクトを作成します。
ここでは、プロジェクト名を「DataSetSample01」とします。

フォームのデザイナを表示させている状態でツールボックスの「データ」カテゴリを展開するとDataSetが存在します。
これをフォーム上にドラッグすることで"DataSetをコンポーネントとして"配置することが可能となります。

しかし今回は"型付きDataSet"を使用するので別手順を踏みます。
ソリューションエクスプローラからDataSetSample01(プロジェクト名)を右クリックし、「追加」→「新しい項目」を選択します。

項目内から「データセット」を選択し、名前を「HomeApplianceDataSet.xsd」とし「追加」をクリックします。

Visual Studioの画面上に追加したDataSetのデザイナが表示されます。

ツールボックスを開くと、DataSetに配置可能なコントロールが表示されます。

今回は「炊飯器」、「冷蔵庫」、「レンジ」用のテーブルを作成する必要があるため、DataTableをデザイナにドラッグしDataSetにDataTableを配置します。
これを3回行い、3つのDataTableを配置します。
配置したDataTableのテーブル名を設定します。
デザイナ上からDataTableを選択し、プロパティを開いてNameプロパティを「炊飯器」に変更します。

DataTableのテーブル名が「炊飯器」になります。

同じ要領で残りのDataTableのテーブル名を「冷蔵庫」と「レンジ」に変更します。
これで、XML内のテーブルに該当する要素名とDataTableのテーブル名が同じとなり関連付けができました。
次は各家電の項目(炊飯器の「メーカー」や「重さ」など)をDataTableの列名と関連付けます。
DataTableを右クリックし、「追加」→「列」を選択します。

DataTableに列が追加されます。

同じ要領で全家電の全項目をDataTableに列として追加していきます。

これで、XML内の各家電の項目に該当する要素名とDataTableの列名も同じとなり関連付けが完了しました。
尚、追加したDataTableの列を選択してプロパティを開き、DataTypeプロパティでStringやInt32など列の型を指定することができます。

UI上でテーブルの構成を作成し、型の指定も行えるのが"型付きDataSet"になります。
後は作成した"型付きDataSet"にXMLファイルを読み込み、フォーム上に表示させます。
フォームのデザイナを開き、ツールボックスからDataGridViewをフォームにドラッグして配置します。
DataGridViewを選択してプロパティを開き、Dockプロパティを「Fill」に設定します。

次は以下のようにコードを記述します。

フォームのロードイベントでDataSetのReadXmlメソッドにXMLファイルのパスを指定することで、関連付けられたテーブルと列に自動でXML内の値が設定されます。
後はDataTableをDataGridViewにバインドしているだけです。
ここでは、「炊飯器」テーブルをバインドしています。

尚、"型付きDataSet"ではテーブルの各列へアクセスするためのプロパティも自動で生成されており、炊飯器の「年間電気代」にアクセスしたければ、以下のようにコード上からアクセスできます。
ds.炊飯器.年間電気代
このように、DataSetへXMLファイルを読み込ませるのはds.ReadXml(~)を行っている1行だけであり、各テーブル、各列へもデザイナ上で設定した名前のままアクセスができるので非常に便利です。
※今回はわかりやすくするため、XMLの項目名やテーブル及び列名などは日本語にしました。
読み込むXMLファイルは以下の通り。

XMLファイルには家電に関する情報を格納し、「炊飯器」、「冷蔵庫」、「レンジ」の簡単な仕様を定義します。
「炊飯器」、「冷蔵庫」、「レンジ」は各々1つのテーブルを表すことになります。
例えば、炊飯器には「メーカー」、「省エネ基準達成率」、「年間電気代」、「重さ」の列が存在し、3つの行が定義されている状態で、DataSetはDataTableの集合を持つため、これが1つのDataTableと関連付くことになります。
DataTableとの関連付けは該当するXML内のタグ名と、DataTableのテーブル名及び列名を同じにすることで自動で行われます。
では、実践してみましょう。
Visual Studioで新規のWindowsフォームアプリケーションのプロジェクトを作成します。
ここでは、プロジェクト名を「DataSetSample01」とします。

フォームのデザイナを表示させている状態でツールボックスの「データ」カテゴリを展開するとDataSetが存在します。
これをフォーム上にドラッグすることで"DataSetをコンポーネントとして"配置することが可能となります。

しかし今回は"型付きDataSet"を使用するので別手順を踏みます。
ソリューションエクスプローラからDataSetSample01(プロジェクト名)を右クリックし、「追加」→「新しい項目」を選択します。

項目内から「データセット」を選択し、名前を「HomeApplianceDataSet.xsd」とし「追加」をクリックします。

Visual Studioの画面上に追加したDataSetのデザイナが表示されます。

ツールボックスを開くと、DataSetに配置可能なコントロールが表示されます。

今回は「炊飯器」、「冷蔵庫」、「レンジ」用のテーブルを作成する必要があるため、DataTableをデザイナにドラッグしDataSetにDataTableを配置します。
これを3回行い、3つのDataTableを配置します。
配置したDataTableのテーブル名を設定します。
デザイナ上からDataTableを選択し、プロパティを開いてNameプロパティを「炊飯器」に変更します。

DataTableのテーブル名が「炊飯器」になります。

同じ要領で残りのDataTableのテーブル名を「冷蔵庫」と「レンジ」に変更します。
これで、XML内のテーブルに該当する要素名とDataTableのテーブル名が同じとなり関連付けができました。
次は各家電の項目(炊飯器の「メーカー」や「重さ」など)をDataTableの列名と関連付けます。
DataTableを右クリックし、「追加」→「列」を選択します。

DataTableに列が追加されます。

同じ要領で全家電の全項目をDataTableに列として追加していきます。

これで、XML内の各家電の項目に該当する要素名とDataTableの列名も同じとなり関連付けが完了しました。
尚、追加したDataTableの列を選択してプロパティを開き、DataTypeプロパティでStringやInt32など列の型を指定することができます。

UI上でテーブルの構成を作成し、型の指定も行えるのが"型付きDataSet"になります。
後は作成した"型付きDataSet"にXMLファイルを読み込み、フォーム上に表示させます。
フォームのデザイナを開き、ツールボックスからDataGridViewをフォームにドラッグして配置します。
DataGridViewを選択してプロパティを開き、Dockプロパティを「Fill」に設定します。

次は以下のようにコードを記述します。

フォームのロードイベントでDataSetのReadXmlメソッドにXMLファイルのパスを指定することで、関連付けられたテーブルと列に自動でXML内の値が設定されます。
後はDataTableをDataGridViewにバインドしているだけです。
ここでは、「炊飯器」テーブルをバインドしています。

尚、"型付きDataSet"ではテーブルの各列へアクセスするためのプロパティも自動で生成されており、炊飯器の「年間電気代」にアクセスしたければ、以下のようにコード上からアクセスできます。
ds.炊飯器.年間電気代
このように、DataSetへXMLファイルを読み込ませるのはds.ReadXml(~)を行っている1行だけであり、各テーブル、各列へもデザイナ上で設定した名前のままアクセスができるので非常に便利です。
※今回はわかりやすくするため、XMLの項目名やテーブル及び列名などは日本語にしました。
| ホーム |