2011-01-20 68 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) ; 

乾杯!