CSVファイル(コンマ区切りのファイル)を読み込む処理は、フィールド自体にコンマが含まれていたり、フィールドがダブルクオーテーションで囲まれていたりする場合などがあり、結構面倒な作業である*。
* CSVファイルの仕様については以前は明確なものがなかったが、現在ではRFC4180により標準化されている。
|
しかし.NET Framework 2.0には、主にVB 2005用の機能として、CSVファイルを読み込み、解析を行ってくれる非常に便利なTextFieldParserクラス(Microsoft.VisualBasic.FileIO名前空間)が追加されている。このクラスを使えば、CSVを読み込んで各行の各フィールドの文字列を簡単に取り出すことができる。
もちろんこのTextFieldParserクラスはC#からも利用可能だ。本稿ではこのクラスを使ってCSVファイルを読み込むための方法について解説する。
TextFieldParserクラスによるCSVファイルの読み込み
TextFieldParserクラスを使用してCSVファイルを読み込むには、まず処理したいCSVファイルをコンストラクタで指定してインスタンスを作成する。
CSVファイルに日本語が含まれている場合には、ここでエンコーディングも指定可能だ(以降のコード例は上がC#、下がVBの場合)。
TextFieldParser parser = new TextFieldParser("text.csv",
System.Text.Encoding.GetEncoding("Shift_JIS"));
|
Dim parser As New TextFieldParser("text.csv", _
System.Text.Encoding.GetEncoding("Shift_JIS"))
|
|
| TextFieldParserクラスのコンストラクタ呼び出し |
次にTextFieldTypeプロパティにFieldType.Delimitedを設定する(FieldType.FixedWidthを指定すればフィールドが固定幅のファイルも扱うことができる)。
また、SetDelimitersメソッドを呼び出して区切り文字を設定しておく(複数の区切り文字が指定可能)。CSVファイルの場合にはもちろんコンマを指定する。
parser.TextFieldType = FieldType.Delimited;
parser.SetDelimiters(","); // 区切り文字はコンマ
|
parser.TextFieldType = FieldType.Delimited
parser.SetDelimiters(",") ' 区切り文字はコンマ
|
|
| フィールドがコンマで区切られている場合の設定 |
あとはReadFieldsメソッドを呼び出すごとに、CSVファイルを1行ずつ読むことができる。このメソッドは、読み込んだ行の全フィールドを文字列の配列として返す。
読み込むべき行がまだ残っているかどうかはEndOfDataプロパティにより判定できるので、次のようなループによりCSVファイル全体を処理できる。
while (!parser.EndOfData) {
string[] row = parser.ReadFields(); // 1行読み込み
// 配列rowの要素は読み込んだ行の各フィールドの値
}
|
While Not parser.EndOfData
Dim row As String() = parser.ReadFields() ' 1行読み込み
' 配列rowの要素は読み込んだ行の各フィールドの値
End While
|
|
| CSVファイル全体を読み込みながら処理するループ |
CSVファイルを読み込み、表示するサンプル・プログラム
次に示すサンプル・プログラムは、CSVファイルであるtext.csvを読み込み、各フィールドを切り出してTAB区切りで画面に出力する。
なおこのプログラムでは、改行文字や空白文字がどのように処理されるかを分かりやすくするために、それぞれを「n」と「_」に置き換えて出力する。
// csvparser.cs
using System;
using Microsoft.VisualBasic.FileIO;
class CSVParser {
static void Main() {
TextFieldParser parser = new TextFieldParser("text.csv",
System.Text.Encoding.GetEncoding("Shift_JIS"));
using (parser) {
parser.TextFieldType = FieldType.Delimited;
parser.SetDelimiters(","); // 区切り文字はコンマ
// parser.HasFieldsEnclosedInQuotes = false;
// parser.TrimWhiteSpace = false;
while (!parser.EndOfData) {
string[] row = parser.ReadFields(); // 1行読み込み
foreach (string field in row) {
string f = field;
f = f.Replace("\r\n", "n"); // 改行をnで表示
f = f.Replace(" ", "_"); // 空白を_で表示
Console.Write(f + "\t"); // TAB区切りで出力
}
Console.WriteLine();
}
}
}
}
// コンパイル方法:csc /r:microsoft.visualbasic.dll csvparser.cs
|
|
| CSVファイルを読み込み、表示するC#のサンプル・プログラム(csvparser.cs) |
|
|
' csvparser.vb
Imports System
Imports Microsoft.VisualBasic.FileIO
Class CSVParser
Shared Sub Main()
Using parser As New TextFieldParser("text.csv", _
System.Text.Encoding.GetEncoding("Shift_JIS"))
parser.TextFieldType = FieldType.Delimited
parser.SetDelimiters(",") ' 区切り文字はコンマ
' parser.HasFieldsEnclosedInQuotes = False
' parser.TrimWhiteSpace = False
While Not parser.EndOfData
Dim row As String() = parser.ReadFields() ' 1行読み込み
For Each field As String In row
field = field.Replace(vbCrLf, "n") ' 改行をnで表示
field = field.Replace(" ", "_") ' 空白を_で表示
Console.Write(field + vbTab) ' TAB区切りで出力
Next
Console.WriteLine()
End While
End Using
End Sub
End Class
' コンパイル方法:vbc csvparser.vb
|
|
| CSVファイルを読み込み、表示するVBのサンプル・プログラム(csvparser.vb) |
|
|
このサンプル・プログラムに次のような内容のCSVファイルを読み込ませた場合の出力を以下に示す。
あああ , いいい , ううう
"あああ" , "いいい" , " ううう "
"あああ" , "い""いい" , "ううう"
"あああ" , "い,いい" , "ううう"
あああ
あああ , いいい
"あああ" , "い
いい","ううう"
|
|
| サンプル・プログラムに読み込ませるCSVファイル(test.csv)の内容 |
| 最後の行は2番目のフィールドの途中に改行が入っている。 |
このCSVファイルを読み込ませた場合のプログラムの出力は次のようになる(実際には出力はTAB区切りとなるが、ここでは分かりやすいように表形式に整形している)。
| あああ |
いいい |
ううう |
| あああ |
いいい |
ううう |
| あああ |
い"いい |
ううう |
| あああ |
い,いい |
ううう |
| あああ |
|
|
| あああ |
いいい |
|
| あああ |
いnいい |
ううう |
|
| サンプル・プログラムの出力結果 |
|
ダブルクオーテーションで囲まれているフィールドや、改行文字が含まれているフィールドも正しく処理されているのが分かる。またデフォルトの設定では、フィールドの前後にある空白文字が自動的に削除されているのも分かる。
■HasFieldsEnclosedInQuotesプロパティ
すべてのフィールドが単純にコンマで区切られているものとして処理したい場合には、HasFieldsEnclosedInQuotesプロパティをfalseに設定する(デフォルトはtrue)。
以下の出力結果は、上記のサンプル・プログラムでこのプロパティをfalseに設定した場合のものである。
| あああ |
いいい |
ううう |
|
| "あああ" |
"いいい" |
"_ううう_" |
|
| "あああ" |
"い""いい" |
"ううう" |
|
| "あああ" |
"い |
いい" |
"ううう" |
| あああ |
|
|
|
| あああ |
いいい |
|
|
| "あああ" |
"い |
|
|
| いい" |
"ううう" |
|
|
|
| HasFieldsEnclosedInQuotes=falseの場合の出力結果 |
|
この場合にはダブルクオーテーションは処理されないのでそのまま出力される。フィールドの途中に改行が入っているデータは2つの行として扱われることになる。
■TrimWhiteSpaceプロパティ
フィールド前後の空白文字を削除したくない場合にはTrimWhiteSpaceプロパティをfalseに設定する(デフォルトはtrue)。
上記のサンプル・プログラムでこのプロパティをfalseに設定した場合の出力結果を以下に示す(HasFieldsEnclosedInQuotesプロパティはtrueのまま)。
| あああ___ |
_いいい_____ |
_ううう |
| あああ |
いいい |
_ううう_ |
| あああ |
い"いい |
ううう |
| あああ |
い,いい |
ううう |
| あああ |
|
|
| あああ___ |
_いいい |
|
| あああ |
いnいい |
ううう |
|
| TrimWhiteSpace=falseの場合の出力結果 |
|
ダブルクオーテーションで囲まれていないフィールドは、区切り文字であるコンマ以外の文字がすべて出力されている。また、ダブルクオーテーションで囲まれているフィールドは、ダブルクオーテーション内のフィールドの前後の空白文字が削除されない