Cómo realizar transformaciones de transmisión por secuencias de texto a XML
Un enfoque del procesamiento de un archivo de texto es escribir un método de extensión que transmita el archivo de texto por secuencias de línea en línea mediante la construcción yield return.Después, puede escribir una consulta LINQ que procese el archivo de texto de forma aplazada y lenta.Si después usa XStreamingElement para transmitir el resultado, puede crear una transformación del archivo de texto al XML usando una cantidad mínima de memoria, independientemente del tamaño del archivo de texto de origen.
Existen algunas advertencias que deben tenerse en cuenta sobre las transformaciones de transmisión por secuencias.Una transformación de transmisión por secuencias se aplica mejor en situaciones en las que se puede procesar todo el archivo, y si se pueden procesar las líneas en el orden en el que se producen en el documento de origen.Si se debe procesar más de un archivo simultáneamente so si se deben ordenar las líneas antes de poder procesarlas, se perderán muchas de las ventajas de utilizar una técnica de transmisión por secuencias.
Ejemplo
El siguiente archivo de texto, People.txt, es el origen de este ejemplo.
#This is a comment
1,Tai,Yee,Writer
2,Nikolay,Grachev,Programmer
3,David,Wright,Inventor
El siguiente código contiene un método de extensión que transmite las líneas del archivo de texto por secuencias de forma diferida.
[!NOTA]
En el ejemplo de código siguiente se utiliza la construcción yield return de C#.En Visual Basic se proporciona código equivalente mediante el uso de una clase que implemente la interfaz IEnumerable(Of XElement).Para obtener un ejemplo de implementación de la interfaz IEnumerable(Of T) en Visual Basic, vea Tutorial: Implementar 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
Este ejemplo genera el siguiente resultado:
<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>