Procédure : effectuer des transformations de diffusion en continu de texte au format XML
L'une des façons de traiter un fichier texte consiste à écrire une méthode d'extension qui diffuse en continu le fichier texte une ligne à la fois à l'aide de la construction yield return. Vous pouvez alors écrire une requête LINQ qui traite le fichier texte de manière différée. Si vous utilisez ensuite XStreamingElement pour diffuser la sortie en continu, vous pouvez créer une transformation du fichier texte en XML qui utilise une quantité minimale de mémoire, quelle que soit la taille du fichier texte source.
Il existe certains points à noter concernant les transformations de diffusion en continu. Il est préférable d'appliquer une transformation de diffusion en continu dans les situations où vous pouvez traiter l'intégralité du fichier une seule fois et si vous pouvez traiter les lignes dans l'ordre dans lequel elles apparaissent dans le document source. Si vous devez traiter le fichier à plusieurs reprises, ou si vous devez trier les lignes avant de les traiter, vous perdez une grande partie des avantages offerts par l'utilisation d'une technique de diffusion en continu.
Exemple
Le fichier texte suivant, People.txt, est la source pour cet exemple.
#This is a comment
1,Tai,Yee,Writer
2,Nikolay,Grachev,Programmer
3,David,Wright,Inventor
Le code suivant contient une méthode d'extension qui diffuse en continu les lignes du fichier texte de manière différée.
Notes
L'exemple suivant utilise la construction yield return de C#.Un code équivalent est fourni dans Visual Basic à l'aide d'une classe qui implémente l'interface IEnumerable(Of XElement).Pour obtenir un exemple d'une implémentation IEnumerable(Of T) dans Visual Basic, consultez Procédure pas à pas : implémentation d'IEnumerable(Of T) en Visual Basic.
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
Cet exemple génère la sortie suivante :
<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>