##状況
DataTableの使い勝手が良いので、CSVやExcelファイルをDataTableに読み込んでゴリゴリ処理したい。
そのためのCSV、Excelファイルのパスを指定したらDataTableに格納して返してくれるメソッドのサンプル。
##ソースと解説
各種ファイルの読み込みにはOLE DB Providerを使ったりするので、下記をusing。
using System.Data;
using System.Data.OleDb;
using System.IO;
###CSVファイル
/// <summary>
/// CSVファイルからDataTableを返す
/// </summary>
/// <param name="strFilePath">CSVファイルパス</param>
/// <param name="isInHeader">1行目はヘッダー扱いとするか</param>
/// <returns></returns>
public static DataTable GetDataTableFromCSV(String strFilePath, Boolean isInHeader = true)
{
DataTable dt = new DataTable();
String strInHeader = isInHeader ? "YES" : "NO"; // ヘッダー設定
String strCon = "Provider=Microsoft.ACE.OLEDB.12.0;" // プロバイダ設定
//= "Provider=Microsoft.Jet.OLEDB.4.0;" // Jetでやる場合
+ "Data Source=" + Path.GetDirectoryName(strFilePath) + "\\; " // ソースファイル指定
+ "Extended Properties=\"Text;HDR=" + strInHeader + ";FMT=Delimited\"";
OleDbConnection con = new OleDbConnection(strCon);
String strCmd = "SELECT * FROM [" + Path.GetFileName(strFilePath) + "]";
// 読み込み
OleDbCommand cmd = new OleDbCommand(strCmd, con);
OleDbDataAdapter adp = new OleDbDataAdapter(cmd);
adp.Fill(dt);
return dt;
}
OLE DB Providerを使って、CSVファイルを読み込み、全選択のSELECT文を発行して全内容を取得している。
読み込むCSVファイルの文字コードはShift-JISである必要がある。
まず、メソッドにはCSVファイルを指定するパスの他にBoolean型のisInHeader
という省略可能なパラメタを用意している。
ソース内では、これでプロバイダの接続文字列にあるHDR=YES;
とHDR=NO;
を切り替えている。
YES
なら1行目をヘッダーとして取り込み、NO
なら1行目からレコードとみなしてDataTableに取り込まれる。
###Excelファイル(1)
/// <summary>
/// Excelファイル(純粋な表)からDataTableを返す
/// </summary>
/// <param name="strFilePath">Excelファイルパス</param>
/// <param name="strSheetName">取り込むシート名</param>
/// <param name="isInHeader">1行目はヘッダー扱いとするか</param>
/// <param name="isAllStrColum">すべて文字列として要素を取得するか</param>
/// <returns></returns>
public static DataTable GetDataTableFromExcelOfPureTable(String strFilePath, String strSheetName, Boolean isInHeader = true, Boolean isAllStrColum = true)
{
DataTable dt = new DataTable();
String strInHeader = isInHeader ? "YES" : "NO"; // ヘッダー設定
String strIMEX = isAllStrColum ? "IMEX=1;" : ""; // 文字列型設定
String strFileEx = Path.GetExtension(strFilePath); // ファイル拡張子
String strExcelVer = "Excel "; // Excelファイルver確認
if (strFileEx == ".xls"){
strExcelVer += "8.0;";
}
else if (strFileEx == ".xlsx" || strFileEx == ".xlsm"){
strExcelVer += "12.0;";
}
else{
return null;
}
String strCon = "Provider=Microsoft.ACE.OLEDB.12.0;" // プロバイダ設定
//= "Provider=Microsoft.Jet.OLEDB.4.0;" // Jetでやる場合(後で検証 xlsxでも使えるのか?)
+ "Data Source=" + strFilePath + "; " // ソースファイル指定
+ "Extended Properties=\"" + strExcelVer // Excelファイルver指定
+ "HDR=" + strInHeader + ";" // ヘッダー設定
+ strIMEX // フィールドの型を強制的にテキスト
+ "\"";
OleDbConnection con = new OleDbConnection(strCon);
String strCmd = "SELECT * FROM [" + strSheetName + "$]";
// 読み込み
OleDbCommand cmd = new OleDbCommand(strCmd, con);
OleDbDataAdapter adp = new OleDbDataAdapter(cmd);
adp.Fill(dt);
return dt;
}
CSVの時同様にOLE DB Providerを使い、全件SELECT文のクエリでデータを取得する。
メソッドの説明に「(純粋な表)」としたように、読み込むExcelファイルはセルA1からヘッダーあるいはレコードが始まるCSVファイルのようなレコードを格納しているだけのExcelファイルによる。
CSVファイルと異なるのは、取得するシートの名前を指定してやること。
それ以外には、拡張子(xls, xlsx, xlsm)から接続文字列を変えていること。他に、デフォルトでは接続文字列にIMEX=1;
というパラメタを加えている。これは、読み取ったセルを強制的にテキスト型として取得するためのもので、指定しないとセルの書式設定によって型を勝手に解釈してくれる(しまう)。
文字と数値が混合する列だった場合、どちらか多い書式に合わせた型になるとかならないとか。私は深くは検証していない。
ちなみに接続文字列に//= "Provider=Microsoft.Jet.OLEDB.4.0;" // Jetでやる場合(後で検証 xlsxでも使えるのか?)
とあるが、これはJetプロバイダの方でxlsxやxlsmといったOffice 2007以降のファイルを読み込めるかどうか検証していないから。
私は最近ACEプロバイダばっかり使ってるので、必要に迫られない限り検証はしない。
###Excelファイル(2)
まだ。これから書く。
##今後の予定とか
純粋な表のみではないExcelファイルとか、この他にAccessファイルからのDataTable取得も追記しようと思っている。
近いうちに。