DoboWiki
Top
> .NETプログラミング研究/65 をテンプレートにして作成
.NETプログラミング研究/65 をテンプレートにして作成
開始行:
#title(.NETプログラミング研究 第65号)
#navi(.NETプログラミング研究)
#contents
*.NETプログラミング研究 第65号 [#q3c81f5f]
**.NET質問箱 [#a3768cfb]
「.NET質問箱」では、「どぼん!のプログラミング掲示板」に...
-[[どぼん!のプログラミング掲示板>https://dobon.net/vb/bb...
***CSV形式のファイルをDataTableや配列等として取得する [#k...
#column(注意){{
この記事の最新版は「[[CSV形式のファイルをDataTableや配列...
}}
''【質問】''
CSV(Comma Separated Value)形式のファイルをDataTableや配...
''【回答】''
これには幾つかの方法が考えられます。ここでは3つの方法を紹...
CSV形式について、絶対的な決まりは存在していないようです。...
-[[CSV Comma Separated Value File Format (How To)>http://...
要約しますと、次のようになります。
1.レコードは、LFまたはCRLFで区切られる。
2.フィールドは、カンマ(,)で区切られる。
3.区切りのカンマの前後のスペース(タブを含む)は無視され...
4.フィールドにカンマが含まれる場合、フィールドをダブルク...
5.フィールドにダブルクォート(")が含まれる場合、フィール...
6.フィールドが改行文字を含む場合、フィールドをダブルクォ...
7.フィールドの前後にスペースがある場合、フィールドをダブ...
8.すべてのフィールドがダブルクォートで囲まれているかもし...
9.はじめのレコードは、ヘッダかもしれない。
ここでは、ここのような決まりに準じて、話を進めることにし...
CSV形式のファイルを配列として取得する方法としてよく使われ...
さて、ここから本題に入ります。まずは、Jet ProviderやODBC ...
以下にJet Providerを使った例を紹介します。ここでは解析さ...
#code(vbnet){{
'CSVファイルのあるフォルダ
Dim csvDir As String = "C:\"
'CSVファイルの名前
Dim csvFileName As String = "test.csv"
'接続文字列
Dim conString As String = _
"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" _
+ csvDir + ";Extended Properties=""text;HDR=No;FMT=De...
Dim con As New System.Data.OleDb.OleDbConnection(conString)
Dim commText As String = "SELECT * FROM [" + csvFileName ...
Dim da As New System.Data.OleDb.OleDbDataAdapter(commText...
'DataTableに格納する
Dim dt As New DataTable
da.Fill(dt)
}}
#code(csharp){{
//CSVファイルのあるフォルダ
string csvDir = @"C:\";
//CSVファイルの名前
string csvFileName = "test.csv";
//接続文字列
string conString = "Provider=Microsoft.Jet.OLEDB.4.0;Data...
+ csvDir + ";Extended Properties=\"text;HDR=No;FMT=De...
System.Data.OleDb.OleDbConnection con =
new System.Data.OleDb.OleDbConnection(conString);
string commText = "SELECT * FROM [" + csvFileName + "]";
System.Data.OleDb.OleDbDataAdapter da =
new System.Data.OleDb.OleDbDataAdapter(commText, con);
//DataTableに格納する
DataTable dt = new DataTable();
da.Fill(dt);
}}
次はODBC Provider(Microsoft Text Driver)を使った例です...
#code(vbnet){{
'CSVファイルのあるフォルダ
Dim csvDir As String = "C:\"
'CSVファイルの名前
Dim csvFileName As String = "test.csv"
'接続文字列
Dim conString As String = _
"Driver={Microsoft Text Driver (*.txt; *.csv)};Dbq=" _
+ csvDir + ";Extensions=asc,csv,tab,txt;"
Dim con As New System.Data.Odbc.OdbcConnection(conString)
Dim commText As String = "SELECT * FROM [" + csvFileName ...
Dim da As New System.Data.Odbc.OdbcDataAdapter(commText, ...
'DataTableに格納する
Dim dt As New DataTable
da.Fill(dt)
}}
#code(csharp){{
//CSVファイルのあるフォルダ
string csvDir = @"C:\";
//CSVファイルの名前
string csvFileName = "test.csv";
//接続文字列
string conString = "Driver={Microsoft Text Driver (*.txt;...
+ csvDir + ";Extensions=asc,csv,tab,txt;";
System.Data.Odbc.OdbcConnection con =
new System.Data.Odbc.OdbcConnection(conString);
string commText = "SELECT * FROM [" + csvFileName + "]";
System.Data.Odbc.OdbcDataAdapter da =
new System.Data.Odbc.OdbcDataAdapter(commText, con);
//DataTableに格納する
DataTable dt = new DataTable();
da.Fill(dt);
}}
このような方法では、正しくCSVファイルが解析されるようにす...
-[[Schema.ini File (Text File Driver)>http://msdn.microso...
Schema.iniファイルの作成法については、次のサイトが参考に...
-[[Importing CSV Data and saving it in database - The Cod...
-[[[AC97]VBAから Schema.ini ファイルを作成する方法>http:/...
参考:
-[[ConnectionStrings.com>http://www.connectionstrings.com...
次に正規表現を使った方法を紹介します。「Perlメモ」の「CSV...
-[[Perlメモ>http://www.din.or.jp/~ohzaki/perl.htm]]
これによると、CSVの一つの行(一つのレコード)からフィール...
("(?:[^"]|"")*"|[^,]*),
というパターンを使用します。
また、フィールドに改行コードを含む場合にCSV形式の文字列か...
フィールドを取り出すためのパターンは、他にもいろいろ考え...
,(?=([^\"]*"[^"]*")*(?![^"]*"))
や
(?:^|,)(\"(?:[^\"]+|\"\")*\"|[^,]*)
などが以下のサイトで紹介されています。
-[[CSV Regex Pattern>http://blogs.worldnomads.com.au/matt...
-[[RegEx for CSV>http://geekswithblogs.net/mwatson/archiv...
「Perlメモ」による方法を参考にしたサンプルを以下に紹介し...
#code(vbnet){{
'/ <summary>
'/ CSVをArrayListに変換
'/ </summary>
'/ <param name="csvText">CSVの内容が入ったString</param>
'/ <returns>変換結果のArrayList</returns>
Public Shared Function CsvToArrayList1(ByVal csvText As S...
As System.Collections.ArrayList
Dim csvRecords As New System.Collections.ArrayList
'前後の改行を削除しておく
csvText = csvText.Trim( _
New Char() {ControlChars.Cr, ControlChars.Lf})
'一行取り出すための正規表現
Dim regLine As New System.Text.RegularExpressions.Reg...
"^.*(?:\n|$)", _
System.Text.RegularExpressions.RegexOptions.Multi...
'1行のCSVから各フィールドを取得するための正規表現
Dim regCsv As New System.Text.RegularExpressions.Rege...
"\s*(""(?:[^""]|"""")*""|[^,]*)\s*,", _
System.Text.RegularExpressions.RegexOptions.None)
Dim mLine As System.Text.RegularExpressions.Match = _
regLine.Match(csvText)
While mLine.Success
'一行取り出す
Dim line As String = mLine.Value
'改行記号が"で囲まれているか調べる
While CountString(line, """") Mod 2 = 1
mLine = mLine.NextMatch()
If Not mLine.Success Then
Throw New ApplicationException("不正なCSV")
End If
line += mLine.Value
End While
'行の最後の改行記号を削除
line = line.TrimEnd( _
New Char() {ControlChars.Cr, ControlChars.Lf})
'最後に「,」をつける
line += ","
'1つの行からフィールドを取り出す
Dim csvFields As New System.Collections.ArrayList
Dim m As System.Text.RegularExpressions.Match = _
regCsv.Match(line)
While m.Success
Dim field As String = m.Groups(1).Value
'前後の空白を削除
field = field.Trim()
'"で囲まれている時
If field.StartsWith("""") And field.EndsWith(...
'前後の"を取る
field = field.Substring(1, field.Length -...
'「""」を「"」にする
field = field.Replace("""""", """")
End If
csvFields.Add(field)
m = m.NextMatch()
End While
csvFields.TrimToSize()
csvRecords.Add(csvFields)
mLine = mLine.NextMatch()
End While
csvRecords.TrimToSize()
Return csvRecords
End Function
'/ <summary>
'/ 指定された文字列内にある文字列が幾つあるか数える
'/ </summary>
'/ <param name="strInput">strFindが幾つあるか数える文字列...
'/ <param name="strFind">数える文字列</param>
'/ <returns>strInput内にstrFindが幾つあったか</returns>
Public Shared Function CountString( _
ByVal strInput As String, _
ByVal strFind As String) As Integer
Dim foundCount As Integer = 0
Dim sPos As Integer = strInput.IndexOf(strFind)
While sPos > -1
foundCount += 1
sPos = strInput.IndexOf(strFind, sPos + 1)
End While
Return foundCount
End Function
}}
#code(csharp){{
/// <summary>
/// CSVをArrayListに変換
/// </summary>
/// <param name="csvText">CSVの内容が入ったString</param>
/// <returns>変換結果のArrayList</returns>
public static System.Collections.ArrayList CsvToArrayList...
{
System.Collections.ArrayList csvRecords =
new System.Collections.ArrayList();
//前後の改行を削除しておく
csvText = csvText.Trim(new char[] {'\r', '\n'});
//一行取り出すための正規表現
System.Text.RegularExpressions.Regex regLine =
new System.Text.RegularExpressions.Regex(
"^.*(?:\\n|$)",
System.Text.RegularExpressions.RegexOptions.Multi...
//1行のCSVから各フィールドを取得するための正規表現
System.Text.RegularExpressions.Regex regCsv =
new System.Text.RegularExpressions.Regex(
"\\s*(\"(?:[^\"]|\"\")*\"|[^,]*)\\s*,",
System.Text.RegularExpressions.RegexOptions.None);
System.Text.RegularExpressions.Match mLine = regLine....
while (mLine.Success)
{
//一行取り出す
string line = mLine.Value;
//改行記号が"で囲まれているか調べる
while ((CountString(line, "\"") % 2) == 1)
{
mLine = mLine.NextMatch();
if (!mLine.Success)
{
throw new ApplicationException("不正なCSV...
}
line += mLine.Value;
}
//行の最後の改行記号を削除
line = line.TrimEnd(new char[] {'\r', '\n'});
//最後に「,」をつける
line += ",";
//1つの行からフィールドを取り出す
System.Collections.ArrayList csvFields =
new System.Collections.ArrayList();
System.Text.RegularExpressions.Match m = regCsv.M...
while (m.Success)
{
string field = m.Groups[1].Value;
//前後の空白を削除
field = field.Trim();
//"で囲まれている時
if (field.StartsWith("\"") && field.EndsWith(...
{
//前後の"を取る
field = field.Substring(1, field.Length -...
//「""」を「"」にする
field = field.Replace("\"\"", "\"");
}
csvFields.Add(field);
m = m.NextMatch();
}
csvFields.TrimToSize();
csvRecords.Add(csvFields);
mLine = mLine.NextMatch();
}
csvRecords.TrimToSize();
return csvRecords;
}
/// <summary>
/// 指定された文字列内にある文字列が幾つあるか数える
/// </summary>
/// <param name="strInput">strFindが幾つあるか数える文字...
/// <param name="strFind">数える文字列</param>
/// <returns>strInput内にstrFindが幾つあったか</returns>
public static int CountString(string strInput, string str...
{
int foundCount = 0;
int sPos = strInput.IndexOf(strFind);
while (sPos > -1)
{
foundCount++;
sPos = strInput.IndexOf(strFind, sPos + 1);
}
return foundCount;
}
}}
最後に紹介するのは、文字列を独自に解析する方法です。面倒...
以下にその例を示します。使い方は先のCsvToArrayList1メソッ...
(テストが十分でないため、間違いがあるかもしれません。不...
#code(vbnet){{
'/ <summary>
'/ CSVをArrayListに変換
'/ </summary>
'/ <param name="csvText">CSVの内容が入ったString</param>
'/ <returns>変換結果のArrayList</returns>
Public Shared Function CsvToArrayList2(ByVal csvText As S...
As System.Collections.ArrayList
'前後の改行を削除しておく
csvText = csvText.Trim( _
New Char() {ControlChars.Cr, ControlChars.Lf})
Dim csvRecords As New System.Collections.ArrayList
Dim csvFields As New System.Collections.ArrayList
Dim csvTextLength As Integer = csvText.Length
Dim startPos As Integer = 0
Dim endPos As Integer = 0
Dim field As String = ""
While True
'空白を飛ばす
While startPos < csvTextLength _
AndAlso (csvText.Chars(startPos) = " "c _
OrElse csvText.Chars(startPos) = ControlChars...
startPos += 1
End While
'データの最後の位置を取得
If startPos < csvTextLength _
AndAlso csvText.Chars(startPos) = ControlChar...
'"で囲まれているとき
'最後の"を探す
endPos = startPos
While True
endPos = csvText.IndexOf(ControlChars.Quo...
If endPos < 0 Then
Throw New ApplicationException("""が...
End If
'"が2つ続かない時は終了
If endPos + 1 = csvTextLength OrElse _
csvText.Chars((endPos + 1)) <> Contro...
Exit While
End If
'"が2つ続く
endPos += 1
End While
'一つのフィールドを取り出す
field = csvText.Substring(startPos, endPos - ...
'""を"にする
field = field.Substring(1, field.Length - 2). _
Replace("""""", """")
endPos += 1
'空白を飛ばす
While endPos < csvTextLength AndAlso _
csvText.Chars(endPos) <> ","c AndAlso _
csvText.Chars(endPos) <> ControlChars.Lf
endPos += 1
End While
Else
'"で囲まれていない
'カンマか改行の位置
endPos = startPos
While endPos < csvTextLength AndAlso _
csvText.Chars(endPos) <> ","c AndAlso _
csvText.Chars(endPos) <> ControlChars.Lf
endPos += 1
End While
'一つのフィールドを取り出す
field = csvText.Substring(startPos, endPos - ...
'後の空白を削除
field = field.TrimEnd()
End If
'フィールドの追加
csvFields.Add(field)
'行の終了か調べる
If endPos >= csvTextLength OrElse _
csvText.Chars(endPos) = ControlChars.Lf Then
'行の終了
'レコードの追加
csvFields.TrimToSize()
csvRecords.Add(csvFields)
csvFields = New System.Collections.ArrayList( _
csvFields.Count)
If endPos >= csvTextLength Then
'終了
Exit While
End If
End If
'次のデータの開始位置
startPos = endPos + 1
End While
csvRecords.TrimToSize()
Return csvRecords
End Function
}}
#code(csharp){{
/// <summary>
/// CSVをArrayListに変換
/// </summary>
/// <param name="csvText">CSVの内容が入ったString</param>
/// <returns>変換結果のArrayList</returns>
public static System.Collections.ArrayList CsvToArrayList...
{
//前後の改行を削除しておく
csvText = csvText.Trim(new char[] {'\r', '\n'});
System.Collections.ArrayList csvRecords =
new System.Collections.ArrayList();
System.Collections.ArrayList csvFields =
new System.Collections.ArrayList();
int csvTextLength = csvText.Length;
int startPos = 0, endPos = 0;
string field = "";
while (true)
{
//空白を飛ばす
while (startPos < csvTextLength &&
(csvText[startPos] == ' ' || csvText[startPos...
{
startPos++;
}
//データの最後の位置を取得
if (startPos < csvTextLength && csvText[startPos]...
{
//"で囲まれているとき
//最後の"を探す
endPos = startPos;
while (true)
{
endPos = csvText.IndexOf('"', endPos + 1);
if (endPos < 0)
{
throw new ApplicationException("\"が...
}
//"が2つ続かない時は終了
if (endPos + 1 == csvTextLength || csvTex...
{
break;
}
//"が2つ続く
endPos++;
}
//一つのフィールドを取り出す
field = csvText.Substring(startPos, endPos - ...
//""を"にする
field = field.Substring(1, field.Length - 2)....
endPos++;
//空白を飛ばす
while (endPos < csvTextLength &&
csvText[endPos] != ',' && csvText[endPos]...
{
endPos++;
}
}
else
{
//"で囲まれていない
//カンマか改行の位置
endPos = startPos;
while (endPos < csvTextLength &&
csvText[endPos] != ',' && csvText[endPos]...
{
endPos++;
}
//一つのフィールドを取り出す
field = csvText.Substring(startPos, endPos - ...
//後の空白を削除
field = field.TrimEnd();
}
//フィールドの追加
csvFields.Add(field);
//行の終了か調べる
if (endPos >= csvTextLength || csvText[endPos] ==...
{
//行の終了
//レコードの追加
csvFields.TrimToSize();
csvRecords.Add(csvFields);
csvFields = new System.Collections.ArrayList(
csvFields.Count);
if (endPos >= csvTextLength)
{
//終了
break;
}
}
//次のデータの開始位置
startPos = endPos + 1;
}
csvRecords.TrimToSize();
return csvRecords;
}
}}
このようなコードを自分で書かなくても、すでに優秀なクラス...
-[[A Fast CSV Reader>http://www.codeproject.com/cs/databa...
-[[XmlCsvReader Implementation>http://msdn.microsoft.com/...
-[[A portable and efficient generic parser for flat files...
-[[ASC2XXX - Two classes for parsing delimited text files...
○この記事の基になった掲示板のスレッド
-[[CSVファイルの総行数を取得したいです。 | 投稿者(敬称略)...
-[[CSV箕荷 | 投稿者(敬称略) kenta, 岡田 之仁, sas>https:/...
-[[CSVファイルをデータグリットで表示 | 投稿者(敬称略) A, ...
-[[CSVファイルについて | 投稿者(敬称略) Boo, 岡田 之仁>ht...
-[[CSVデータをODBCで削除するには? | 投稿者(敬称略) おす...
-[[テキストファイルを実行ファイルに取り込んで扱う方法 | ...
-[[ArrayListの使い方 | 投稿者(敬称略) kyoro, Blue, 中博俊...
-[[多次元配列(二次元配列)の初期化について | 投稿者(敬称...
-[[Split | 投稿者(敬称略) SOMY, まどか, なおこ(・∀・)>htt...
***DataTableや配列等をCSV形式のファイルとして保存する [#f...
#column(注意){{
この記事の最新版は「[[DataTableや配列等をCSV形式のファイ...
}}
''【質問】''
DataTableや配列をCSV形式のファイルとして保存するにはどの...
【解答】
ここでもCSV形式の規則は、先ほど紹介したものと同じとして、...
このような方針により、DataTableをCSV形式のファイルに保存...
またこの例では、いちいち一つ一つのフィールドを調べてダブ...
#code(vbnet){{
'CSVで保存するDataTable
Dim dt As DataTable = CType(DataGrid1.DataSource, DataTab...
'保存先のCSVファイルのパス
Dim csvPath As String = "C:\test1.csv"
'CSVファイルに書き込むときに使うEncoding
Dim enc As System.Text.Encoding = _
System.Text.Encoding.GetEncoding("Shift_JIS")
'開く
Dim sr As New System.IO.StreamWriter(csvPath, False, enc)
Dim colCount As Integer = dt.Columns.Count
Dim lastColIndex As Integer = colCount - 1
'ヘッダを書き込む
Dim i As Integer
For i = 0 To colCount - 1
'ヘッダの取得
Dim field As String = dt.Columns(i).Caption
'"で囲む必要があるか調べる
If field.IndexOf(ControlChars.Quote) > -1 OrElse _
field.IndexOf(","c) > -1 OrElse _
field.IndexOf(ControlChars.Cr) > -1 OrElse _
field.IndexOf(ControlChars.Lf) > -1 OrElse _
field.StartsWith(" ") OrElse _
field.StartsWith(ControlChars.Tab) OrElse _
field.EndsWith(" ") OrElse _
field.EndsWith(ControlChars.Tab) Then
If field.IndexOf(ControlChars.Quote) > -1 Then
'"を""とする
field = field.Replace("""", """""")
End If
field = """" + field + """"
End If
'フィールドを書き込む
sr.Write(field)
'カンマを書き込む
If lastColIndex > i Then
sr.Write(","c)
End If
Next i
'改行する
sr.Write(ControlChars.Cr + ControlChars.Lf)
'レコードを書き込む
Dim row As DataRow
For Each row In dt.Rows
For i = 0 To colCount - 1
'フィールドの取得
Dim field As String = row(i).ToString()
'"で囲む必要があるか調べる
If field.IndexOf(ControlChars.Quote) > -1 OrElse _
field.IndexOf(","c) > -1 OrElse _
field.IndexOf(ControlChars.Cr) > -1 OrElse _
field.IndexOf(ControlChars.Lf) > -1 OrElse _
field.StartsWith(" ") OrElse _
field.StartsWith(ControlChars.Tab) OrElse _
field.EndsWith(" ") OrElse _
field.EndsWith(ControlChars.Tab) Then
If field.IndexOf(ControlChars.Quote) > -1 Then
'"を""とする
field = field.Replace("""", """""")
End If
field = """" + field + """"
End If
'フィールドを書き込む
sr.Write(field)
'カンマを書き込む
If lastColIndex > i Then
sr.Write(","c)
End If
Next i
'改行する
sr.Write(ControlChars.Cr + ControlChars.Lf)
Next row
'閉じる
sr.Close()
}}
#code(csharp){{
//CSVで保存するDataTable
DataTable dt = (DataTable) dataGrid1.DataSource;
//保存先のCSVファイルのパス
string csvPath = "C:\\test1.csv";
//CSVファイルに書き込むときに使うEncoding
System.Text.Encoding enc =
System.Text.Encoding.GetEncoding("Shift_JIS");
//開く
System.IO.StreamWriter sr =
new System.IO.StreamWriter(csvPath, false, enc);
int colCount = dt.Columns.Count;
int lastColIndex = colCount - 1;
//ヘッダを書き込む
for (int i = 0; i < colCount; i++)
{
//ヘッダの取得
string field = dt.Columns[i].Caption;
//"で囲む必要があるか調べる
if (field.IndexOf('"') > -1 ||
field.IndexOf(',') > -1 ||
field.IndexOf('\r') > -1 ||
field.IndexOf('\n') > -1 ||
field.StartsWith(" ") || field.StartsWith("\t") ||
field.EndsWith(" ") || field.EndsWith("\t"))
{
if (field.IndexOf('"') > -1)
{
//"を""とする
field = field.Replace("\"", "\"\"");
}
field = "\"" + field + "\"";
}
//フィールドを書き込む
sr.Write(field);
//カンマを書き込む
if (lastColIndex > i)
{
sr.Write(',');
}
}
//改行する
sr.Write("\r\n");
//レコードを書き込む
foreach (DataRow row in dt.Rows)
{
for (int i = 0; i < colCount; i++)
{
//フィールドの取得
string field = row[i].ToString();
//"で囲む必要があるか調べる
if (field.IndexOf('"') > -1 ||
field.IndexOf(',') > -1 ||
field.IndexOf('\r') > -1 ||
field.IndexOf('\n') > -1 ||
field.StartsWith(" ") || field.StartsWith("\t...
field.EndsWith(" ") || field.EndsWith("\t"))
{
if (field.IndexOf('"') > -1)
{
//"を""とする
field = field.Replace("\"", "\"\"");
}
field = "\"" + field + "\"";
}
//フィールドを書き込む
sr.Write(field);
//カンマを書き込む
if (lastColIndex > i)
{
sr.Write(',');
}
}
//改行する
sr.Write("\r\n");
}
//閉じる
sr.Close();
}}
このような方法以外に、掲示板では、XSLTを使ってCSVに変換す...
-[[XSLT to transform Excel XML spreadsheet to CSV or HTML...
-[[XSLT to Convert Dataset XML to CSV>http://groups.googl...
私個人の意見としましては、このような方法では上記に示したC...
○この記事の基になった掲示板のスレッド
-[[csvファイルの読み書き | 投稿者(敬称略) KIRIRI, なおこ(...
-[[DatasetのデータをCSV保存する | 投稿者(敬称略) ほげほげ...
-[[ADO.NETからの出力結果のカラム名を取り出すには? | 投稿...
**コメント [#nd32bb27]
#comment
//これより下は編集しないでください
#pageinfo([[:Category/.NET]],2006-02-19 (日) 18:00:00,DOB...
終了行:
#title(.NETプログラミング研究 第65号)
#navi(.NETプログラミング研究)
#contents
*.NETプログラミング研究 第65号 [#q3c81f5f]
**.NET質問箱 [#a3768cfb]
「.NET質問箱」では、「どぼん!のプログラミング掲示板」に...
-[[どぼん!のプログラミング掲示板>https://dobon.net/vb/bb...
***CSV形式のファイルをDataTableや配列等として取得する [#k...
#column(注意){{
この記事の最新版は「[[CSV形式のファイルをDataTableや配列...
}}
''【質問】''
CSV(Comma Separated Value)形式のファイルをDataTableや配...
''【回答】''
これには幾つかの方法が考えられます。ここでは3つの方法を紹...
CSV形式について、絶対的な決まりは存在していないようです。...
-[[CSV Comma Separated Value File Format (How To)>http://...
要約しますと、次のようになります。
1.レコードは、LFまたはCRLFで区切られる。
2.フィールドは、カンマ(,)で区切られる。
3.区切りのカンマの前後のスペース(タブを含む)は無視され...
4.フィールドにカンマが含まれる場合、フィールドをダブルク...
5.フィールドにダブルクォート(")が含まれる場合、フィール...
6.フィールドが改行文字を含む場合、フィールドをダブルクォ...
7.フィールドの前後にスペースがある場合、フィールドをダブ...
8.すべてのフィールドがダブルクォートで囲まれているかもし...
9.はじめのレコードは、ヘッダかもしれない。
ここでは、ここのような決まりに準じて、話を進めることにし...
CSV形式のファイルを配列として取得する方法としてよく使われ...
さて、ここから本題に入ります。まずは、Jet ProviderやODBC ...
以下にJet Providerを使った例を紹介します。ここでは解析さ...
#code(vbnet){{
'CSVファイルのあるフォルダ
Dim csvDir As String = "C:\"
'CSVファイルの名前
Dim csvFileName As String = "test.csv"
'接続文字列
Dim conString As String = _
"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" _
+ csvDir + ";Extended Properties=""text;HDR=No;FMT=De...
Dim con As New System.Data.OleDb.OleDbConnection(conString)
Dim commText As String = "SELECT * FROM [" + csvFileName ...
Dim da As New System.Data.OleDb.OleDbDataAdapter(commText...
'DataTableに格納する
Dim dt As New DataTable
da.Fill(dt)
}}
#code(csharp){{
//CSVファイルのあるフォルダ
string csvDir = @"C:\";
//CSVファイルの名前
string csvFileName = "test.csv";
//接続文字列
string conString = "Provider=Microsoft.Jet.OLEDB.4.0;Data...
+ csvDir + ";Extended Properties=\"text;HDR=No;FMT=De...
System.Data.OleDb.OleDbConnection con =
new System.Data.OleDb.OleDbConnection(conString);
string commText = "SELECT * FROM [" + csvFileName + "]";
System.Data.OleDb.OleDbDataAdapter da =
new System.Data.OleDb.OleDbDataAdapter(commText, con);
//DataTableに格納する
DataTable dt = new DataTable();
da.Fill(dt);
}}
次はODBC Provider(Microsoft Text Driver)を使った例です...
#code(vbnet){{
'CSVファイルのあるフォルダ
Dim csvDir As String = "C:\"
'CSVファイルの名前
Dim csvFileName As String = "test.csv"
'接続文字列
Dim conString As String = _
"Driver={Microsoft Text Driver (*.txt; *.csv)};Dbq=" _
+ csvDir + ";Extensions=asc,csv,tab,txt;"
Dim con As New System.Data.Odbc.OdbcConnection(conString)
Dim commText As String = "SELECT * FROM [" + csvFileName ...
Dim da As New System.Data.Odbc.OdbcDataAdapter(commText, ...
'DataTableに格納する
Dim dt As New DataTable
da.Fill(dt)
}}
#code(csharp){{
//CSVファイルのあるフォルダ
string csvDir = @"C:\";
//CSVファイルの名前
string csvFileName = "test.csv";
//接続文字列
string conString = "Driver={Microsoft Text Driver (*.txt;...
+ csvDir + ";Extensions=asc,csv,tab,txt;";
System.Data.Odbc.OdbcConnection con =
new System.Data.Odbc.OdbcConnection(conString);
string commText = "SELECT * FROM [" + csvFileName + "]";
System.Data.Odbc.OdbcDataAdapter da =
new System.Data.Odbc.OdbcDataAdapter(commText, con);
//DataTableに格納する
DataTable dt = new DataTable();
da.Fill(dt);
}}
このような方法では、正しくCSVファイルが解析されるようにす...
-[[Schema.ini File (Text File Driver)>http://msdn.microso...
Schema.iniファイルの作成法については、次のサイトが参考に...
-[[Importing CSV Data and saving it in database - The Cod...
-[[[AC97]VBAから Schema.ini ファイルを作成する方法>http:/...
参考:
-[[ConnectionStrings.com>http://www.connectionstrings.com...
次に正規表現を使った方法を紹介します。「Perlメモ」の「CSV...
-[[Perlメモ>http://www.din.or.jp/~ohzaki/perl.htm]]
これによると、CSVの一つの行(一つのレコード)からフィール...
("(?:[^"]|"")*"|[^,]*),
というパターンを使用します。
また、フィールドに改行コードを含む場合にCSV形式の文字列か...
フィールドを取り出すためのパターンは、他にもいろいろ考え...
,(?=([^\"]*"[^"]*")*(?![^"]*"))
や
(?:^|,)(\"(?:[^\"]+|\"\")*\"|[^,]*)
などが以下のサイトで紹介されています。
-[[CSV Regex Pattern>http://blogs.worldnomads.com.au/matt...
-[[RegEx for CSV>http://geekswithblogs.net/mwatson/archiv...
「Perlメモ」による方法を参考にしたサンプルを以下に紹介し...
#code(vbnet){{
'/ <summary>
'/ CSVをArrayListに変換
'/ </summary>
'/ <param name="csvText">CSVの内容が入ったString</param>
'/ <returns>変換結果のArrayList</returns>
Public Shared Function CsvToArrayList1(ByVal csvText As S...
As System.Collections.ArrayList
Dim csvRecords As New System.Collections.ArrayList
'前後の改行を削除しておく
csvText = csvText.Trim( _
New Char() {ControlChars.Cr, ControlChars.Lf})
'一行取り出すための正規表現
Dim regLine As New System.Text.RegularExpressions.Reg...
"^.*(?:\n|$)", _
System.Text.RegularExpressions.RegexOptions.Multi...
'1行のCSVから各フィールドを取得するための正規表現
Dim regCsv As New System.Text.RegularExpressions.Rege...
"\s*(""(?:[^""]|"""")*""|[^,]*)\s*,", _
System.Text.RegularExpressions.RegexOptions.None)
Dim mLine As System.Text.RegularExpressions.Match = _
regLine.Match(csvText)
While mLine.Success
'一行取り出す
Dim line As String = mLine.Value
'改行記号が"で囲まれているか調べる
While CountString(line, """") Mod 2 = 1
mLine = mLine.NextMatch()
If Not mLine.Success Then
Throw New ApplicationException("不正なCSV")
End If
line += mLine.Value
End While
'行の最後の改行記号を削除
line = line.TrimEnd( _
New Char() {ControlChars.Cr, ControlChars.Lf})
'最後に「,」をつける
line += ","
'1つの行からフィールドを取り出す
Dim csvFields As New System.Collections.ArrayList
Dim m As System.Text.RegularExpressions.Match = _
regCsv.Match(line)
While m.Success
Dim field As String = m.Groups(1).Value
'前後の空白を削除
field = field.Trim()
'"で囲まれている時
If field.StartsWith("""") And field.EndsWith(...
'前後の"を取る
field = field.Substring(1, field.Length -...
'「""」を「"」にする
field = field.Replace("""""", """")
End If
csvFields.Add(field)
m = m.NextMatch()
End While
csvFields.TrimToSize()
csvRecords.Add(csvFields)
mLine = mLine.NextMatch()
End While
csvRecords.TrimToSize()
Return csvRecords
End Function
'/ <summary>
'/ 指定された文字列内にある文字列が幾つあるか数える
'/ </summary>
'/ <param name="strInput">strFindが幾つあるか数える文字列...
'/ <param name="strFind">数える文字列</param>
'/ <returns>strInput内にstrFindが幾つあったか</returns>
Public Shared Function CountString( _
ByVal strInput As String, _
ByVal strFind As String) As Integer
Dim foundCount As Integer = 0
Dim sPos As Integer = strInput.IndexOf(strFind)
While sPos > -1
foundCount += 1
sPos = strInput.IndexOf(strFind, sPos + 1)
End While
Return foundCount
End Function
}}
#code(csharp){{
/// <summary>
/// CSVをArrayListに変換
/// </summary>
/// <param name="csvText">CSVの内容が入ったString</param>
/// <returns>変換結果のArrayList</returns>
public static System.Collections.ArrayList CsvToArrayList...
{
System.Collections.ArrayList csvRecords =
new System.Collections.ArrayList();
//前後の改行を削除しておく
csvText = csvText.Trim(new char[] {'\r', '\n'});
//一行取り出すための正規表現
System.Text.RegularExpressions.Regex regLine =
new System.Text.RegularExpressions.Regex(
"^.*(?:\\n|$)",
System.Text.RegularExpressions.RegexOptions.Multi...
//1行のCSVから各フィールドを取得するための正規表現
System.Text.RegularExpressions.Regex regCsv =
new System.Text.RegularExpressions.Regex(
"\\s*(\"(?:[^\"]|\"\")*\"|[^,]*)\\s*,",
System.Text.RegularExpressions.RegexOptions.None);
System.Text.RegularExpressions.Match mLine = regLine....
while (mLine.Success)
{
//一行取り出す
string line = mLine.Value;
//改行記号が"で囲まれているか調べる
while ((CountString(line, "\"") % 2) == 1)
{
mLine = mLine.NextMatch();
if (!mLine.Success)
{
throw new ApplicationException("不正なCSV...
}
line += mLine.Value;
}
//行の最後の改行記号を削除
line = line.TrimEnd(new char[] {'\r', '\n'});
//最後に「,」をつける
line += ",";
//1つの行からフィールドを取り出す
System.Collections.ArrayList csvFields =
new System.Collections.ArrayList();
System.Text.RegularExpressions.Match m = regCsv.M...
while (m.Success)
{
string field = m.Groups[1].Value;
//前後の空白を削除
field = field.Trim();
//"で囲まれている時
if (field.StartsWith("\"") && field.EndsWith(...
{
//前後の"を取る
field = field.Substring(1, field.Length -...
//「""」を「"」にする
field = field.Replace("\"\"", "\"");
}
csvFields.Add(field);
m = m.NextMatch();
}
csvFields.TrimToSize();
csvRecords.Add(csvFields);
mLine = mLine.NextMatch();
}
csvRecords.TrimToSize();
return csvRecords;
}
/// <summary>
/// 指定された文字列内にある文字列が幾つあるか数える
/// </summary>
/// <param name="strInput">strFindが幾つあるか数える文字...
/// <param name="strFind">数える文字列</param>
/// <returns>strInput内にstrFindが幾つあったか</returns>
public static int CountString(string strInput, string str...
{
int foundCount = 0;
int sPos = strInput.IndexOf(strFind);
while (sPos > -1)
{
foundCount++;
sPos = strInput.IndexOf(strFind, sPos + 1);
}
return foundCount;
}
}}
最後に紹介するのは、文字列を独自に解析する方法です。面倒...
以下にその例を示します。使い方は先のCsvToArrayList1メソッ...
(テストが十分でないため、間違いがあるかもしれません。不...
#code(vbnet){{
'/ <summary>
'/ CSVをArrayListに変換
'/ </summary>
'/ <param name="csvText">CSVの内容が入ったString</param>
'/ <returns>変換結果のArrayList</returns>
Public Shared Function CsvToArrayList2(ByVal csvText As S...
As System.Collections.ArrayList
'前後の改行を削除しておく
csvText = csvText.Trim( _
New Char() {ControlChars.Cr, ControlChars.Lf})
Dim csvRecords As New System.Collections.ArrayList
Dim csvFields As New System.Collections.ArrayList
Dim csvTextLength As Integer = csvText.Length
Dim startPos As Integer = 0
Dim endPos As Integer = 0
Dim field As String = ""
While True
'空白を飛ばす
While startPos < csvTextLength _
AndAlso (csvText.Chars(startPos) = " "c _
OrElse csvText.Chars(startPos) = ControlChars...
startPos += 1
End While
'データの最後の位置を取得
If startPos < csvTextLength _
AndAlso csvText.Chars(startPos) = ControlChar...
'"で囲まれているとき
'最後の"を探す
endPos = startPos
While True
endPos = csvText.IndexOf(ControlChars.Quo...
If endPos < 0 Then
Throw New ApplicationException("""が...
End If
'"が2つ続かない時は終了
If endPos + 1 = csvTextLength OrElse _
csvText.Chars((endPos + 1)) <> Contro...
Exit While
End If
'"が2つ続く
endPos += 1
End While
'一つのフィールドを取り出す
field = csvText.Substring(startPos, endPos - ...
'""を"にする
field = field.Substring(1, field.Length - 2). _
Replace("""""", """")
endPos += 1
'空白を飛ばす
While endPos < csvTextLength AndAlso _
csvText.Chars(endPos) <> ","c AndAlso _
csvText.Chars(endPos) <> ControlChars.Lf
endPos += 1
End While
Else
'"で囲まれていない
'カンマか改行の位置
endPos = startPos
While endPos < csvTextLength AndAlso _
csvText.Chars(endPos) <> ","c AndAlso _
csvText.Chars(endPos) <> ControlChars.Lf
endPos += 1
End While
'一つのフィールドを取り出す
field = csvText.Substring(startPos, endPos - ...
'後の空白を削除
field = field.TrimEnd()
End If
'フィールドの追加
csvFields.Add(field)
'行の終了か調べる
If endPos >= csvTextLength OrElse _
csvText.Chars(endPos) = ControlChars.Lf Then
'行の終了
'レコードの追加
csvFields.TrimToSize()
csvRecords.Add(csvFields)
csvFields = New System.Collections.ArrayList( _
csvFields.Count)
If endPos >= csvTextLength Then
'終了
Exit While
End If
End If
'次のデータの開始位置
startPos = endPos + 1
End While
csvRecords.TrimToSize()
Return csvRecords
End Function
}}
#code(csharp){{
/// <summary>
/// CSVをArrayListに変換
/// </summary>
/// <param name="csvText">CSVの内容が入ったString</param>
/// <returns>変換結果のArrayList</returns>
public static System.Collections.ArrayList CsvToArrayList...
{
//前後の改行を削除しておく
csvText = csvText.Trim(new char[] {'\r', '\n'});
System.Collections.ArrayList csvRecords =
new System.Collections.ArrayList();
System.Collections.ArrayList csvFields =
new System.Collections.ArrayList();
int csvTextLength = csvText.Length;
int startPos = 0, endPos = 0;
string field = "";
while (true)
{
//空白を飛ばす
while (startPos < csvTextLength &&
(csvText[startPos] == ' ' || csvText[startPos...
{
startPos++;
}
//データの最後の位置を取得
if (startPos < csvTextLength && csvText[startPos]...
{
//"で囲まれているとき
//最後の"を探す
endPos = startPos;
while (true)
{
endPos = csvText.IndexOf('"', endPos + 1);
if (endPos < 0)
{
throw new ApplicationException("\"が...
}
//"が2つ続かない時は終了
if (endPos + 1 == csvTextLength || csvTex...
{
break;
}
//"が2つ続く
endPos++;
}
//一つのフィールドを取り出す
field = csvText.Substring(startPos, endPos - ...
//""を"にする
field = field.Substring(1, field.Length - 2)....
endPos++;
//空白を飛ばす
while (endPos < csvTextLength &&
csvText[endPos] != ',' && csvText[endPos]...
{
endPos++;
}
}
else
{
//"で囲まれていない
//カンマか改行の位置
endPos = startPos;
while (endPos < csvTextLength &&
csvText[endPos] != ',' && csvText[endPos]...
{
endPos++;
}
//一つのフィールドを取り出す
field = csvText.Substring(startPos, endPos - ...
//後の空白を削除
field = field.TrimEnd();
}
//フィールドの追加
csvFields.Add(field);
//行の終了か調べる
if (endPos >= csvTextLength || csvText[endPos] ==...
{
//行の終了
//レコードの追加
csvFields.TrimToSize();
csvRecords.Add(csvFields);
csvFields = new System.Collections.ArrayList(
csvFields.Count);
if (endPos >= csvTextLength)
{
//終了
break;
}
}
//次のデータの開始位置
startPos = endPos + 1;
}
csvRecords.TrimToSize();
return csvRecords;
}
}}
このようなコードを自分で書かなくても、すでに優秀なクラス...
-[[A Fast CSV Reader>http://www.codeproject.com/cs/databa...
-[[XmlCsvReader Implementation>http://msdn.microsoft.com/...
-[[A portable and efficient generic parser for flat files...
-[[ASC2XXX - Two classes for parsing delimited text files...
○この記事の基になった掲示板のスレッド
-[[CSVファイルの総行数を取得したいです。 | 投稿者(敬称略)...
-[[CSV箕荷 | 投稿者(敬称略) kenta, 岡田 之仁, sas>https:/...
-[[CSVファイルをデータグリットで表示 | 投稿者(敬称略) A, ...
-[[CSVファイルについて | 投稿者(敬称略) Boo, 岡田 之仁>ht...
-[[CSVデータをODBCで削除するには? | 投稿者(敬称略) おす...
-[[テキストファイルを実行ファイルに取り込んで扱う方法 | ...
-[[ArrayListの使い方 | 投稿者(敬称略) kyoro, Blue, 中博俊...
-[[多次元配列(二次元配列)の初期化について | 投稿者(敬称...
-[[Split | 投稿者(敬称略) SOMY, まどか, なおこ(・∀・)>htt...
***DataTableや配列等をCSV形式のファイルとして保存する [#f...
#column(注意){{
この記事の最新版は「[[DataTableや配列等をCSV形式のファイ...
}}
''【質問】''
DataTableや配列をCSV形式のファイルとして保存するにはどの...
【解答】
ここでもCSV形式の規則は、先ほど紹介したものと同じとして、...
このような方針により、DataTableをCSV形式のファイルに保存...
またこの例では、いちいち一つ一つのフィールドを調べてダブ...
#code(vbnet){{
'CSVで保存するDataTable
Dim dt As DataTable = CType(DataGrid1.DataSource, DataTab...
'保存先のCSVファイルのパス
Dim csvPath As String = "C:\test1.csv"
'CSVファイルに書き込むときに使うEncoding
Dim enc As System.Text.Encoding = _
System.Text.Encoding.GetEncoding("Shift_JIS")
'開く
Dim sr As New System.IO.StreamWriter(csvPath, False, enc)
Dim colCount As Integer = dt.Columns.Count
Dim lastColIndex As Integer = colCount - 1
'ヘッダを書き込む
Dim i As Integer
For i = 0 To colCount - 1
'ヘッダの取得
Dim field As String = dt.Columns(i).Caption
'"で囲む必要があるか調べる
If field.IndexOf(ControlChars.Quote) > -1 OrElse _
field.IndexOf(","c) > -1 OrElse _
field.IndexOf(ControlChars.Cr) > -1 OrElse _
field.IndexOf(ControlChars.Lf) > -1 OrElse _
field.StartsWith(" ") OrElse _
field.StartsWith(ControlChars.Tab) OrElse _
field.EndsWith(" ") OrElse _
field.EndsWith(ControlChars.Tab) Then
If field.IndexOf(ControlChars.Quote) > -1 Then
'"を""とする
field = field.Replace("""", """""")
End If
field = """" + field + """"
End If
'フィールドを書き込む
sr.Write(field)
'カンマを書き込む
If lastColIndex > i Then
sr.Write(","c)
End If
Next i
'改行する
sr.Write(ControlChars.Cr + ControlChars.Lf)
'レコードを書き込む
Dim row As DataRow
For Each row In dt.Rows
For i = 0 To colCount - 1
'フィールドの取得
Dim field As String = row(i).ToString()
'"で囲む必要があるか調べる
If field.IndexOf(ControlChars.Quote) > -1 OrElse _
field.IndexOf(","c) > -1 OrElse _
field.IndexOf(ControlChars.Cr) > -1 OrElse _
field.IndexOf(ControlChars.Lf) > -1 OrElse _
field.StartsWith(" ") OrElse _
field.StartsWith(ControlChars.Tab) OrElse _
field.EndsWith(" ") OrElse _
field.EndsWith(ControlChars.Tab) Then
If field.IndexOf(ControlChars.Quote) > -1 Then
'"を""とする
field = field.Replace("""", """""")
End If
field = """" + field + """"
End If
'フィールドを書き込む
sr.Write(field)
'カンマを書き込む
If lastColIndex > i Then
sr.Write(","c)
End If
Next i
'改行する
sr.Write(ControlChars.Cr + ControlChars.Lf)
Next row
'閉じる
sr.Close()
}}
#code(csharp){{
//CSVで保存するDataTable
DataTable dt = (DataTable) dataGrid1.DataSource;
//保存先のCSVファイルのパス
string csvPath = "C:\\test1.csv";
//CSVファイルに書き込むときに使うEncoding
System.Text.Encoding enc =
System.Text.Encoding.GetEncoding("Shift_JIS");
//開く
System.IO.StreamWriter sr =
new System.IO.StreamWriter(csvPath, false, enc);
int colCount = dt.Columns.Count;
int lastColIndex = colCount - 1;
//ヘッダを書き込む
for (int i = 0; i < colCount; i++)
{
//ヘッダの取得
string field = dt.Columns[i].Caption;
//"で囲む必要があるか調べる
if (field.IndexOf('"') > -1 ||
field.IndexOf(',') > -1 ||
field.IndexOf('\r') > -1 ||
field.IndexOf('\n') > -1 ||
field.StartsWith(" ") || field.StartsWith("\t") ||
field.EndsWith(" ") || field.EndsWith("\t"))
{
if (field.IndexOf('"') > -1)
{
//"を""とする
field = field.Replace("\"", "\"\"");
}
field = "\"" + field + "\"";
}
//フィールドを書き込む
sr.Write(field);
//カンマを書き込む
if (lastColIndex > i)
{
sr.Write(',');
}
}
//改行する
sr.Write("\r\n");
//レコードを書き込む
foreach (DataRow row in dt.Rows)
{
for (int i = 0; i < colCount; i++)
{
//フィールドの取得
string field = row[i].ToString();
//"で囲む必要があるか調べる
if (field.IndexOf('"') > -1 ||
field.IndexOf(',') > -1 ||
field.IndexOf('\r') > -1 ||
field.IndexOf('\n') > -1 ||
field.StartsWith(" ") || field.StartsWith("\t...
field.EndsWith(" ") || field.EndsWith("\t"))
{
if (field.IndexOf('"') > -1)
{
//"を""とする
field = field.Replace("\"", "\"\"");
}
field = "\"" + field + "\"";
}
//フィールドを書き込む
sr.Write(field);
//カンマを書き込む
if (lastColIndex > i)
{
sr.Write(',');
}
}
//改行する
sr.Write("\r\n");
}
//閉じる
sr.Close();
}}
このような方法以外に、掲示板では、XSLTを使ってCSVに変換す...
-[[XSLT to transform Excel XML spreadsheet to CSV or HTML...
-[[XSLT to Convert Dataset XML to CSV>http://groups.googl...
私個人の意見としましては、このような方法では上記に示したC...
○この記事の基になった掲示板のスレッド
-[[csvファイルの読み書き | 投稿者(敬称略) KIRIRI, なおこ(...
-[[DatasetのデータをCSV保存する | 投稿者(敬称略) ほげほげ...
-[[ADO.NETからの出力結果のカラム名を取り出すには? | 投稿...
**コメント [#nd32bb27]
#comment
//これより下は編集しないでください
#pageinfo([[:Category/.NET]],2006-02-19 (日) 18:00:00,DOB...
ページ名:
▲
▼
[
トップ
] [
新規
|
子ページ作成
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
]