XmlReader从固定长度缓冲区读取

时间:2011-01-20 23:46:07

标签: c# xml

传入流来自固定的1024字节缓冲区,流本身是一个拥抱XML文件,可能需要几轮读取才能完成。我的目标是读取缓冲区并计算元素在大型XML文件中出现的次数。

我的挑战是,因为它实际上是一个固定长度的缓冲区,所以它不能保证XML的良好形式,如果我将流包装在XmlTextReader中,我总是得到异常并且无法完成读取。例如,元素可以是abcdef,而第一个缓冲区可以以abc结束,而第二个缓冲区以def开始。我真的很沮丧,任何人都可以建议一个更好的方法来使用流媒体时尚来实现这个目标吗? (我不想在内存中加载整个内容)

非常感谢

2 个答案:

答案 0 :(得分:2)

你的1024字节缓冲区是否来自System.IO.Stream的标准具体实现之一?如果是,您可以围绕基本流创建XmlTextReader:

XmlTextReader tr = XmlTextReader.Create( myStreamInstance ) ;

如果不是 - 例如,比如说,你正在从某种API“读取”缓冲区 - 你需要实现自己的具体Stream,就像这些一样(你需要做的就是充实了) ReadNextFrame()方法并可能实现你的构造函数):

public class MyStream : System.IO.Stream
{
    public override bool CanRead  { get { return true  ; } }
    public override bool CanSeek  { get { return false ; } }
    public override bool CanWrite { get { return false ; } }
    public override long Length   { get { throw new NotImplementedException(); } }
    public override long Position {
                                    get { throw new NotImplementedException(); }
                                    set { throw new NotImplementedException(); }
                                  }

    public override int Read( byte[] buffer , int offset , int count )
    {
        int bytesRead = 0 ;

        if ( !initialized )
        {
            Initialize() ;
        }

        for ( int bytesRemaining = count ; !atEOF && bytesRemaining > 0 ; )
        {

            int frameRemaining = frameLength - frameOffset ;
            int chunkSize      = ( bytesRemaining > frameRemaining ? frameRemaining : bytesRemaining ) ;

            Array.Copy( frame , offset , frame , frameOffset , chunkSize ) ;

            bytesRemaining -= chunkSize ;
            offset         += chunkSize ;
            bytesRead      += chunkSize ;

            // read next frame if necessary
            if ( frameOffset >= frameLength )
            {
                ReadNextFrame() ;
            }

        }

        return bytesRead ;
    }

    public override long Seek( long offset , System.IO.SeekOrigin origin ) { throw new NotImplementedException(); }
    public override void SetLength( long value )                           { throw new NotImplementedException(); }
    public override void Write( byte[] buffer , int offset , int count )   { throw new NotImplementedException(); }
    public override void Flush()                                           { throw new NotImplementedException(); }

    private byte[] frame       = null  ;
    private int    frameLength = 0     ;
    private int    frameOffset = 0     ;
    private bool   atEOF       = false ;
    private bool   initialized = false ;

    private void Initialize()
    {
        if ( initialized ) throw new InvalidOperationException() ;

        frame       = new byte[1024] ;
        frameLength = 0 ;
        frameOffset = 0 ;
        atEOF       = false ;
        initialized = true ;

        ReadNextFrame() ;

        return ;
    }

    private void ReadNextFrame()
    {

        //TODO: read the next (or first 1024-byte buffer
        //TODO: set the frame length to the number of bytes actually returned (might be less than 1024 on the last read, right?
        //TODO: set the frame offset to 0
        //TODO: set the atEOF flag if we've exhausted the data source ;

        return ;

    }

}

然后如上所述实例化你的XmlReader:

System.IO.Stream     s  = new MyStream() ;
System.Xml.XmlReader xr = XmlTextReader.Create( s ) ;

干杯!

答案 1 :(得分:0)

这是一个奇怪的目标...通常它更像是“计数元素但不会将整个XML加载到内存”这是微不足道的 - 写一个Stream派生类,它代表你缓冲区作为前向唯一流(类似于NetworkStream)和通常使用XmlReader读取XML(即使用LINQ),但不构造XmlDocument。

如果您澄清目标,其他人可能会更容易提出建议。