CSVファイルの定義は以下の通りです。
1.レコードは、CRLFで区切られる。
2.フィールドの数は、同じである。
3.フィールドは、[区切文字]で区切られる。
4.フィールドに[区切文字]が含まれる場合、そのフィールドはダブルクォートで囲まれている。
例)区切文字を「,(カンマ)」とした場合、○"field,111" ×fied,222
5.フィールドにダブルクォートが含まれる場合、そのフィールドはダブルクォートで囲まれており、
フィールド内のダブルクォートを2つの連続するダブルクォートに置き換えている。
例)○"field""111" ×"fied"222" ×field"333
ReadToDataTableメソッドは引数に指定したCSVファイルを
引数に指定したエンコードで読み込み、引数にしていした区切文字でフィールドに区切り、DataTabaleを返します。
引数に指定したisFirstTitleがtrueの場合、CSVファイルの先頭行はDataTableの列名になります。falseの場合はField1,Field2・・・となります。
2010/04/09
「CSVのフィールド数は同じである」としましたが、フィールド数がバラバラなCSVも存在しているのでそれらを読み込めるように修正しました。
あとバグもあったのでコッソリ修正しました。
Public Class CsvFile ''' <summary> ''' 1行づつ読み取りString配列で返す。 ''' </summary> ''' <param name="path">CSVファイルパス</param> ''' <param name="enc">エンコード</param> ''' <remarks></remarks> Public Shared Function Read(ByVal path As String, ByVal enc As System.Text.Encoding) As String() Return System.IO.File.ReadAllLines(path, enc) End Function ''' <summary> ''' 指定したファイルから、指定した区切文字でフィールドに区切り、DataTableで返す。 ''' </summary> ''' <param name="path">読み取るファイルのパス</param> ''' <param name="enc">エンコード</param> ''' <param name="cSeparator">区切文字</param> ''' <param name="isFirstTitle">1行目がタイトルかどうか</param> ''' <param name="sTblName">DataTable名</param> ''' <returns></returns> ''' <remarks></remarks> Public Shared Function ReadToDataTable(ByVal path As String, ByVal enc As System.Text.Encoding, ByVal cSeparator As Char, ByVal isFirstTitle As Boolean, ByVal sTblName As String) As DataTable 'ファイルから読み込み Dim sLines As String() = Read(path, enc) 'ファイルから読み込んだデータを分解し、リストに格納 Dim lstRows As New List(Of String()) For Each line As String In sLines '--行を分解しString配列にする。 Dim fields As String() = LineToArray(line, cSeparator) lstRows.Add(fields) Next '読み込んだデータより最大列数を取得する Dim iMaxField As Integer For Each fields As String() In lstRows If iMaxField < fields.Length Then iMaxField = fields.Length End If Next 'テーブルに列を追加する。 Dim tbl As New DataTable(sTblName) For idx As Integer = 0 To iMaxField - 1 tbl.Columns.Add("Field" & (idx + 1), GetType(String)) Next 'テーブルにデータを追加する。 For iRow As Integer = 0 To lstRows.Count - 1 Dim fields As String() = lstRows(iRow) If isFirstTitle AndAlso iRow = 0 Then For iCol As Integer = 0 To fields.Length - 1 tbl.Columns(iCol).ColumnName = fields(iCol) Next Else Dim newrow As DataRow = tbl.NewRow For iCol As Integer = 0 To fields.Length - 1 newrow(iCol) = fields(iCol) Next tbl.Rows.Add(newrow) End If Next 'Test出力 '-------------------- For idx As Integer = 0 To tbl.Columns.Count - 1 If idx <> 0 Then Console.Write(",") Console.Write(tbl.Columns(idx).ColumnName) Next Console.WriteLine("") Console.WriteLine("-------------------------------") For Each row As DataRow In tbl.Rows For idx As Integer = 0 To row.ItemArray.Length - 1 If idx <> 0 Then Console.Write(",") Console.Write(row(idx)) Next Console.WriteLine("") Next '-------------------- Return tbl End Function ''' <summary> ''' ファイルから読み取った1行分の文字列データを、引数に指定した区切り文字に従って分解し、String配列で返す ''' </summary> ''' <param name="line">ファイルから読み取った1行分の文字列データ</param> ''' <param name="cSeparator"></param> ''' <returns></returns> ''' <remarks></remarks> Public Shared Function LineToArray(ByVal line As String, ByVal cSeparator As Char) As String() Dim lstField As New List(Of String) For iSt As Integer = 0 To line.Length - 1 'フィールドの開始が"で始まっているかを判定 Dim isWQuote As Boolean = False If line(iSt) = Chr(34) Then isWQuote = True iSt += 1 End If 'フィールドの終了位置を検索 Dim sFind As String If isWQuote Then sFind = Chr(34) + cSeparator Else sFind = cSeparator End If Dim iEd As Integer = line.IndexOf(sFind, iSt) If iEd = -1 Then iEd = line.Length If isWQuote Then If line(iEd - 1) = Chr(34) Then iEd = line.Length - 1 End If End If End If 'フィールドを取得 Dim sField As String sField = line.Substring(iSt, (iEd - iSt)) 'フィールドから2つの連続するダブルクォートを1つのダブルクォートに置換する sField = sField.Replace(Chr(34) + Chr(34), Chr(34)) 'フィールドを追加 lstField.Add(sField) '開始インデックスをずらす If isWQuote Then iSt = iEd + 1 Else iSt = iEd End If Next Return lstField.ToArray End Function End Class使用方法
Dim path As String = System.IO.Path.Combine(Application.StartupPath, "Test.csv") Dim enc As System.Text.Encoding = System.Text.Encoding.GetEncoding("Shift_Jis") 'カンマ区切り Dim tbl As DataTable = NvTool.File.CsvFile.ReadToDataTable(path, enc, ","c, True, "Test") 'Tab区切り Dim tbl As DataTable = NvTool.File.CsvFile.ReadToDataTable(path, enc, Chr(9), True, "Test")
0 件のコメント:
コメントを投稿