繁体   English   中英

XmlReader从固定长度的缓冲区读取

[英]XmlReader to read from fixed length buffer

传入流进入一个固定的1024字节缓冲区,该流本身是一个拥抱XML文件,可能需要经过几轮读取才能完成。 我的目标是读取缓冲区并找出元素在大型XML文件中出现了多少次。

我的挑战是,因为它实际上是一个固定长度的缓冲区,所以它不能保证XML的格式,如果将流包装在XmlTextReader中,则总是会出现异常,并且无法完成读取。 例如,元素可以是abcdef,而第一个缓冲区可以以abc结束,而第二个缓冲区以def开头。 我对此感到非常沮丧,任何人都可以建议一种更好的方式来使用流媒体方式来归档此文件? (我不想将全部内容加载到内存中)

非常感谢

您的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 ) ;

干杯!

这有点奇怪的目标……通常更像是“计数元素,但不将整个XML加载到内存中”,这很简单-写Stream派生类,将您的缓冲区表示为仅转发流(类似于NetworkStream),然后读取XML(即使用LINQ)通常使用XmlReader,但不要构造XmlDocument。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM