.net(VB、C#)でLINQを利用してCSVファイルを読み込む
LINQでCSVファイルを読み込む
.NETには、CSVファイルを読み取る際に便利なクラス(TextFieldParser)が「VB.NET」のライブラリに存在する。
このクラスを利用してCSVファイルをLINQで簡潔に扱えるようにする。
まず、CSVファイルへのコンテキストを生成する為のTextFieldクラスを作成する。
このクラスのContextメソッドでコンテキストを生成することでロジックを意識することなくCSVファイルの読み込みが可能になる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | Imports System.Text Imports System.IO Imports Microsoft.VisualBasic.FileIO Public Class TextField ' 指定されたCSVファイルへのコンテキストを生成する Public Shared Function Context(path As String, Optional separator As String = ",", Optional myEncoding As Encoding = Nothing) As IEnumerable(Of String()) Dim results As New List(Of String()) Using stream As Stream = New FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read) Using parser As New TextFieldParser(stream, If(myEncoding, Encoding.UTF8), True, False) parser.TextFieldType = FieldType.Delimited parser.Delimiters = New String() {separator} parser.HasFieldsEnclosedInQuotes = True parser.TrimWhiteSpace = True While parser.EndOfData = False Dim fields As String() = parser.ReadFields() results.Add(fields) End While End Using End Using Return results End Function End Class |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using Microsoft.VisualBasic.FileIO; namespace CS_CSVtoLINQ { public class TextField { // 指定されたCSVファイルへのコンテキストを生成する public static IEnumerable<string[]> Context(string path, string separator = ",", Encoding encoding = null) { using (Stream stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) { using (TextFieldParser parser = new TextFieldParser(stream, encoding ?? Encoding.UTF8, true, false)) { parser.TextFieldType = FieldType.Delimited; parser.Delimiters = new[] { separator }; parser.HasFieldsEnclosedInQuotes = true; parser.TrimWhiteSpace = true; while (parser.EndOfData == false) { string[] fields = parser.ReadFields(); yield return fields; } } } } } } |
次は、実際にTextFieldクラスを利用してコンテキストを生成し、CSVファイルへアクセスしてLINQにより入力した条件に一致するレコードデータを表示するコードを記述する。
尚、AsParallel()メソッドを呼び出すことで条件判定をマルチスレッド化できるので、データ量が多い場合は、並列化による高速化が期待できる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | Imports System.Text Imports System.IO Module Module1 Sub Main() Do ' 検索条件に使用するIDの入力を求める Console.WriteLine("IDを入力") Dim input As String = Console.ReadLine() ' 入力された値から終了判定 If input.ToUpper = "END" OrElse input.ToUpper = "EXIT" Then ' "END"、または"EXIT"が入力された場合は終了 Exit Do End If ' 指定したCSVファイルへのコンテキストを生成 Dim context As IEnumerable(Of String()) = TextField.Context("CSV\\SAMPLE001.csv", ",", Encoding.GetEncoding("Shift_JIS")) ' 取得したコンテキストを入力されたIDをキーに検索 Dim results As IEnumerable(Of String) = From fields In context.AsParallel() Where fields(0).Equals(input) Select String.Format("{0}:{1}", fields(1), fields(2)) ' 検索結果を出力 For Each result As String In results Console.WriteLine(result) Next Console.WriteLine("---END---") Loop End Sub End Module |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace CS_CSVtoLINQ { class Program { static void Main(string[] args) { while (true) { // 検索条件に使用するIDの入力を求める Console.WriteLine("IDを入力"); string input = Console.ReadLine(); // 入力された値から終了判定 if (input.ToUpper().Equals("END") || input.ToUpper().Equals("EXIT")) { // "END"、または"EXIT"が入力された場合は終了 break; } // 指定したCSVファイルへのコンテキストを生成 IEnumerable<string[]> context = TextField.Context("CSV\\SAMPLE001.csv", ",", Encoding.GetEncoding("Shift_JIS")); // 取得したコンテキストを入力されたIDをキーに検索 IEnumerable<string> results = from fields in context.AsParallel() where fields[0].Equals(input) select String.Format("{0}:{1}", fields[1], fields[2]); // 検索結果を出力 foreach (string result in results) { Console.WriteLine(result); } Console.WriteLine("---END---"); } } } } |
複数ファイルを跨いで検索する場合は以下のように記述することができる。
※全てのファイルレイアウトが同じ場合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | Imports System.Text Imports System.IO Module Module1 Sub Main() Do ' 検索条件に使用するIDの入力を求める Console.WriteLine("IDを入力") Dim input As String = Console.ReadLine() ' 入力された値から終了判定 If input.ToUpper = "END" OrElse input.ToUpper = "EXIT" Then ' "END"、または"EXIT"が入力された場合は終了 Exit Do End If ' 指定したCSVファイルへのコンテキストを生成して、入力されたIDをキーに検索 Dim results As IEnumerable(Of String) = From path In Directory.GetFiles("CSV", "*.csv", SearchOption.AllDirectories).AsParallel() From fields In TextField.Context(path, ",", Encoding.GetEncoding("Shift_JIS")) Where fields(0).Equals(input) Select String.Format("{0}:{1}", fields(1), fields(2)) ' 検索結果を出力 For Each result As String In results Console.WriteLine(result) Next Console.WriteLine("---END---") Loop End Sub End Module |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; namespace CS_CSVtoLINQ { class Program { static void Main(string[] args) { while (true) { // 検索条件に使用するIDの入力を求める Console.WriteLine("IDを入力"); string input = Console.ReadLine(); // 入力された値から終了判定 if (input.ToUpper().Equals("END") || input.ToUpper().Equals("EXIT")) { // "END"、または"EXIT"が入力された場合は終了 break; } // 指定したCSVファイルへのコンテキストを生成して、入力されたIDをキーに検索 IEnumerable<string> results = from path in Directory.GetFiles("CSV", "*.csv", SearchOption.AllDirectories).AsParallel() from fields in TextField.Context(path, ",", Encoding.GetEncoding("Shift_JIS")) where fields[0].Equals(input) select String.Format("{0}:{1}", fields[1], fields[2]); // 検索結果を出力 foreach (string result in results) { Console.WriteLine(result); } Console.WriteLine("---END---"); } } } } |