テキスト ファイルを処理する方法の 1 つは、yield return 構造を使用して、テキスト ファイルを一度に 1 行ずつストリーム出力する拡張メソッドを記述することです。その後、テキスト ファイルをレイジー遅延方式で処理する LINQ クエリを記述できます。次に XStreamingElement を使用してストリーム出力すると、ソース テキスト ファイルのサイズにかかわらず、メモリを最小限しか使用しないテキスト ファイルから XML への変換を作成できます。
ストリーミング変換に関しては、いくつかの注意事項があります。ストリーミング変換は、ファイル全体の処理を 1 回で行うことが可能で、かつソース ドキュメント内の順番どおりに行を処理できる場合に適しています。ファイルを 2 回以上処理する必要がある場合、または処理前に行を並べ替える必要がある場合は、ストリーミングの手法が持つ多くの利点を活かすことはできません。
使用例
次のテキスト ファイル (People.txt) は、この例のソースです。
#This is a comment
1,Tai,Yee,Writer
2,Nikolay,Grachev,Programmer
3,David,Wright,Inventor
次のコードには、このテキスト ファイルの行を遅延方式でストリーム出力する拡張メソッドが含まれています。
注意
次の例では、C# の yield return 構造を使用します。Visual Basic で、IEnumerable(Of XElement) インターフェイスを実装するクラスを使用した同等のコードが提供されています。Visual Basic で IEnumerable(Of T) を実装する例は、「チュートリアル: Visual Basic での IEnumerable(Of T) の実装」を参照してください。
public static class StreamReaderSequence
{
public static IEnumerable<string> Lines(this StreamReader source)
{
String line;
if (source == null)
throw new ArgumentNullException("source");
while ((line = source.ReadLine()) != null)
{
yield return line;
}
}
}
class Program
{
static void Main(string[] args)
{
StreamReader sr = new StreamReader("People.txt");
XStreamingElement xmlTree = new XStreamingElement("Root",
from line in sr.Lines()
let items = line.Split(',')
where !line.StartsWith("#")
select new XElement("Person",
new XAttribute("ID", items[0]),
new XElement("First", items[1]),
new XElement("Last", items[2]),
new XElement("Occupation", items[3])
)
);
Console.WriteLine(xmlTree);
sr.Close();
}
}
Module Module1
Sub Main()
Dim sr = New IO.StreamReader("..\..\People.txt")
Dim xmlTree = New XStreamingElement("Root",
From line In sr.Lines()
Let items = Split(line, ",")
Where Not line.StartsWith("#")
Select <Person ID=<%= items(0) %>>
<First><%= items(1) %></First>
<Last><%= items(2) %></Last>
<Occupation><%= items(3) %></Occupation>
</Person>
)
Console.WriteLine(xmlTree)
sr.Close()
End Sub
End Module
Module StreamReaderSequence
<System.Runtime.CompilerServices.Extension()>
Public Function Lines(ByRef source As IO.StreamReader) As IEnumerable(Of String)
If source Is Nothing Then Throw New ArgumentNullException("source")
Return New StreamReaderEnumerable(source)
End Function
End Module
Public Class StreamReaderEnumerable
Implements IEnumerable(Of String)
Private _source As IO.StreamReader
Public Sub New(ByVal source As IO.StreamReader)
_source = source
End Sub
Public Function GetEnumerator() As Generic.IEnumerator(Of String) Implements IEnumerable(Of String).GetEnumerator
Return New StreamReaderEnumerator(_source)
End Function
Public Function GetEnumerator1() As IEnumerator Implements IEnumerable.GetEnumerator
Return Me.GetEnumerator()
End Function
End Class
Public Class StreamReaderEnumerator
Implements IEnumerator(Of String)
Private _current As String
Private _source As IO.StreamReader
Public Sub New(ByVal source As IO.StreamReader)
_source = source
End Sub
Public ReadOnly Property Current As String Implements Generic.IEnumerator(Of String).Current
Get
Return _current
End Get
End Property
Public ReadOnly Property Current1 As Object Implements IEnumerator.Current
Get
Return Me.Current
End Get
End Property
Public Function MoveNext() As Boolean Implements IEnumerator.MoveNext
_current = _source.ReadLine()
Return If(_current IsNot Nothing, True, False)
End Function
Public Sub Reset() Implements IEnumerator.Reset
_current = Nothing
_source.DiscardBufferedData()
_source.BaseStream.Seek(0, IO.SeekOrigin.Begin)
End Sub
Public Sub Dispose() Implements IDisposable.Dispose
End Sub
End Class
この例を実行すると、次の出力が生成されます。
<Root>
<Person ID="1">
<First>Tai</First>
<Last>Yee</Last>
<Occupation>Writer</Occupation>
</Person>
<Person ID="2">
<First>Nikolay</First>
<Last>Grachev</Last>
<Occupation>Programmer</Occupation>
</Person>
<Person ID="3">
<First>David</First>
<Last>Wright</Last>
<Occupation>Inventor</Occupation>
</Person>
</Root>