2011-01-20 111 views
0

传入流进来一个固定的1024字节缓冲区,流本身是一个拥抱XML文件,可能需要几轮阅读才能完成。我的目标是读取缓冲区并确定大XML文件中发生元素的次数。XmlReader从固定长度的缓冲区读取

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

非常感谢

+0

XmlTextReader应该是解决方案,只需让它管理缓冲区而不是手动执行。 – porges 2011-01-20 23:54:52

回答

0

这是有点怪的目标...通常它更像是“计数元素,但不会加载整个XML记忆”,这是trivial - 写Stream派生类,它代表你缓冲为仅向前流(类似于NetworkStream)并且通常使用XmlReader读取XML(即使用LINQ),但不要构造XmlDocument。

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

+0

感谢Alex的回复。这种情况是在BizTalk中的管道组件的事件处理程序中编写代码。在运行时,BizTalk引擎将读取下游数据(以xml格式),然后引发事件并为事件处理程序提供固定长度的缓冲区。我的目标是以某种方式消耗此缓冲区来计算某个元素。但是,这个问题的挑战在于缓冲区内没有什么保证,因为部分非空洞的xml可以在内部。 – NINIThePug 2011-01-21 00:47:15

1

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

XmlTextReader tr = XmlTextReader.Create(myStreamInstance) ; 

如果不是 - 比方说,比如,你从某种API的“读书”的缓冲区 - 你需要实现自己的具体流,沿着这些线路(你应该需要做的是割肉出局的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) ; 

干杯!