Partilhar via


Como: Executar transformações de fluxo contínuo de texto para XML

Uma abordagem para processar um arquivo de texto é escrever um método de extensão que passa o arquivo de texto uma linha em uma hora usando a compilação de yield return . Você então pode escrever uma consulta LINQ que processa o arquivo de texto em uma forma adiada lazy. Se você usar XStreamingElement para passar saída, então você pode criar uma transformação de arquivo de texto para XML que usa uma quantidade mínima de memória, independentemente do tamanho do arquivo de texto de origem.

Há algumas restrições em relação às transformações de streaming. Uma transformação de streaming é aplicada melhor em situações onde você pode processar o arquivo inteiro uma vez, e se você pode processar linhas na ordem que ocorrem no documento de origem. Se você precisa processar o arquivo mais de uma vez, ou se você precisa classificar as linhas antes que você possa processar as, você perderá muitos benefícios de usar uma técnica de streaming.

Exemplo

O seguinte arquivo de texto, People.txt, é a fonte para esse exemplo.

#This is a comment
1,Tai,Yee,Writer
2,Nikolay,Grachev,Programmer
3,David,Wright,Inventor

O código a seguir contém um método de extensão que passa as linhas do arquivo de texto em uma forma adiada.

Dica

O exemplo a seguir usa a construção yield return de C#.O código equivalente é fornecido no Visual Basic usando uma classe que implementa a interface IEnumerable(Of XElement).Para obter um exemplo de implementação de IEnumerable(Of T) no Visual Basic, consulte Instruções passo a passo: implementando IEnumerable(Of T) no 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 exemplo gera a seguinte saída:

<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>

Consulte também

Referência

XStreamingElement

Conceitos

Técnicas avançadas de consulta (LINQ to XML)