2015-05-19 20 views
1

我有一個客戶端程序,它接收來自遠程服務器的流XML消息。這些流提供各種體育賽事的實時更新,並且永久運行;即使沒有更新傳輸,它仍然每45秒發送一次保持活動消息。StreamReader替代方案將空字符( 0)視爲行結尾

有問題的服務有兩個不同的細節提要。第一個feed用一個回車符/換行符(0d,0a)終止每個XML消息,這意味着使用StreamReader非常容易。 EG:

using (TcpClient Client = new TcpClient(this.Host, this.Port)) 
{ 
    using (NetworkStream stream = Client.GetStream()) 
    { 
     StreamReader reader = new StreamReader(stream); 
     while (!reader.EndOfStream) 
     { 
     String message = reader.ReadLine(); 
     ProcessMessage(message); 
     } 
    } 
} 

第二饋送,但是,不與CR/LF而只用空字符(\ 0),這StreamReader.ReadLine()不把作爲線的末端,所以它終止永遠等待永遠不會到來的東西。

我無法首先將其寫入文件,但我無法讓公司提供的提要改變任何內容,因爲它已被別人使用。

是否有替代StreamReader的將考慮空char作爲行尾終止符?

+0

一些有趣的解決方案[這裏](http://stackoverflow.com/questions/667771/c-sharp-streamreader-readline-need-to-pick-up-line-terminators)。詞法分析器和全局替換。 – lloyd

+1

只需編寫您自己的Stream類,類似於BufferedStream,即可將'\ 0'轉換爲\ r \ n。 –

+0

可能比Stream更適合實現自定義Reader。 – glenebob

回答

0

CustomStreamReader類 - 終止於'\ 0'或'\ r \ n'。我已經用基於文件的流和MemoryStream進行了測試,我想NetworkStream應該不會有太大的不同....讓我知道你是怎麼去的!

我還在本文結尾處包含了我的TestHarness中的重要代碼,在使用MemoryStream時,我有一些極端的奇怪點,在讀取之前將流位設置爲max。

我真的沒有太多的信用,大部分這只是從現有的StreamReader從微軟參考源提取必要的部分...幾個小時左右才能成功修改和測試。

CustomStreamReader

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Linq; 
using System.Runtime; 
using System.Runtime.CompilerServices; 
using System.Security; 
using System.Text; 
using System.Threading.Tasks; 

namespace StreamReaderOverride 
{ 
    public class CustomStreamReader : StreamReader 
    { 
     private int charPos; 

     private int charLen; 

     private int byteLen; 

     private Encoding encoding; 

     private bool _isBlocked; 

     private byte[] byteBuffer; 

     private Decoder decoder; 

     private int bytePos; 

     private bool _checkPreamble; 

     private bool _detectEncoding; 

     private Stream stream; 

     private volatile Task _asyncReadTask; 

     private char[] charBuffer; 

     private byte[] _preamble; 

     private bool _closable; 

     public bool EndOfStream; 

     private int _maxCharsPerBuffer; 

     public CustomStreamReader(Stream stream): this(stream, Encoding.UTF8, true, DefaultBufferSize, false) 
     { 

     } 

     public CustomStreamReader(string path): this(path, Encoding.UTF8, true, DefaultBufferSize, false) 
     { 

     } 

     public CustomStreamReader(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize, bool leaveOpen): base(stream, Encoding.UTF8, detectEncodingFromByteOrderMarks, bufferSize, false) 
     { 
      if (stream == null || encoding == null) 
      { 
       throw new ArgumentNullException((stream == null) ? "stream" : "encoding"); 
      } 
      if (!stream.CanRead) 
      { 
       throw new ArgumentException(GetResourceString("Argument_StreamNotReadable")); 
      } 
      if (bufferSize <= 0) 
      { 
       throw new ArgumentOutOfRangeException("bufferSize", GetResourceString("ArgumentOutOfRange_NeedPosNum")); 
      } 
      this.Init(stream, encoding, detectEncodingFromByteOrderMarks, bufferSize, leaveOpen); 
     } 

     internal CustomStreamReader(string path, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize, bool checkHost): base(path, Encoding.UTF8, detectEncodingFromByteOrderMarks, bufferSize) 
     { 
      if (path == null || encoding == null) 
      { 
       throw new ArgumentNullException((path == null) ? "path" : "encoding"); 
      } 
      if (path.Length == 0) 
      { 
       throw new ArgumentException(GetResourceString("Argument_EmptyPath")); 
      } 
      if (bufferSize <= 0) 
      { 
       throw new ArgumentOutOfRangeException("bufferSize", GetResourceString("ArgumentOutOfRange_NeedPosNum")); 
      } 
      Stream stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, false); 
      this.Init(stream, encoding, detectEncodingFromByteOrderMarks, bufferSize, false); 
     } 

     internal static int DefaultBufferSize 
     { 
      get 
      { 
       return 1024; 
      } 
     } 


     private void Init(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize, bool leaveOpen) 
     { 
      this.stream = stream; 
      this.encoding = encoding; 
      this.decoder = encoding.GetDecoder(); 
      if (bufferSize < 128) 
      { 
       bufferSize = 128; 
      } 
      this.byteBuffer = new byte[bufferSize]; 
      this._maxCharsPerBuffer = encoding.GetMaxCharCount(bufferSize); 
      this.charBuffer = new char[this._maxCharsPerBuffer]; 
      this.byteLen = 0; 
      this.bytePos = 0; 
      this._detectEncoding = detectEncodingFromByteOrderMarks; 
      this._preamble = encoding.GetPreamble(); 
      this._checkPreamble = (this._preamble.Length > 0); 
      this._isBlocked = false; 
      this._closable = !leaveOpen; 
     } 

     private void CheckAsyncTaskInProgress() 
     { 
      Task asyncReadTask = this._asyncReadTask; 
      if (asyncReadTask != null && !asyncReadTask.IsCompleted) 
      { 
       throw new InvalidOperationException(GetResourceString("InvalidOperation_AsyncIOInProgress")); 
      } 
     } 

     public string ReadLineOrNullString() 
     {    
      if (this.stream == null) 
      { 
       return null; 
      } 
      this.CheckAsyncTaskInProgress(); 
      if (this.charPos == this.charLen && this.ReadBuffer() == 0) 
      { 
       return null; 
      } 

      StringBuilder stringBuilder = null; 
      int num; 
      char c; 
      while (true) 
      { 
       num = this.charPos; 
       do 
       { 
        c = this.charBuffer[num]; 
        if (c == '\r' || c == '\n' || c == '\0') 
        { 
         goto IL_4A; 
        } 

        num++; 
       } 
       while (num < this.charLen); 
       num = this.charLen - this.charPos; 
       if (stringBuilder == null) 
       { 
        stringBuilder = new StringBuilder(num + 80); 
       } 
       stringBuilder.Append(this.charBuffer, this.charPos, num); 
       if (this.ReadBuffer() <= 0) 
       { 
        goto Block_11; 
       } 
      } 
     IL_4A: 
      string result; 
      if (stringBuilder != null) 
      { 
       stringBuilder.Append(this.charBuffer, this.charPos, num - this.charPos); 
       result = stringBuilder.ToString(); 
      } 
      else 
      { 
       result = new string(this.charBuffer, this.charPos, num - this.charPos); 
      } 
      this.charPos = num + 1; 
      if ((c == '\r' && (this.charPos < this.charLen || this.ReadBuffer() > 0) && this.charBuffer[this.charPos] == '\n')) 
      { 
       this.charPos++; 
      } 
      if (this.charPos >= this.charLen) 
      { 
       this.EndOfStream = true; 
      } 
      return result; 
     Block_11: 
      return stringBuilder.ToString(); 
     } 

     internal virtual int ReadBuffer() 
     { 
      this.charLen = 0; 
      this.charPos = 0; 
      if (!this._checkPreamble) 
      { 
       this.byteLen = 0; 
      } 
      while (true) 
      { 
       if (this._checkPreamble) 
       { 
        int num = this.stream.Read(this.byteBuffer, this.bytePos, this.byteBuffer.Length - this.bytePos); 
        if (num == 0) 
        { 
         break; 
        } 
        this.byteLen += num; 
       } 
       else 
       { 
        this.byteLen = this.stream.Read(this.byteBuffer, 0, this.byteBuffer.Length); 
        if (this.byteLen == 0) 
        { 
         goto Block_5; 
        } 
       } 
       this._isBlocked = (this.byteLen < this.byteBuffer.Length); 
       if (!this.IsPreamble()) 
       { 
        if (this._detectEncoding && this.byteLen >= 2) 
        { 
         this.DetectEncoding(); 
        } 
        this.charLen += this.decoder.GetChars(this.byteBuffer, 0, this.byteLen, this.charBuffer, this.charLen); 
       } 
       if (this.charLen != 0) 
       { 
        goto Block_9; 
       } 
      } 
      if (this.byteLen > 0) 
      { 
       this.charLen += this.decoder.GetChars(this.byteBuffer, 0, this.byteLen, this.charBuffer, this.charLen); 
       this.bytePos = (this.byteLen = 0); 
      } 
      return this.charLen; 
     Block_5: 
      return this.charLen; 
     Block_9: 
      return this.charLen; 
     } 

     private bool IsPreamble() 
     { 
      if (!this._checkPreamble) 
      { 
       return this._checkPreamble; 
      } 
      int num = (this.byteLen >= this._preamble.Length) ? (this._preamble.Length - this.bytePos) : (this.byteLen - this.bytePos); 
      int i = 0; 
      while (i < num) 
      { 
       if (this.byteBuffer[this.bytePos] != this._preamble[this.bytePos]) 
       { 
        this.bytePos = 0; 
        this._checkPreamble = false; 
        break; 
       } 
       i++; 
       this.bytePos++; 
      } 
      if (this._checkPreamble && this.bytePos == this._preamble.Length) 
      { 
       this.CompressBuffer(this._preamble.Length); 
       this.bytePos = 0; 
       this._checkPreamble = false; 
       this._detectEncoding = false; 
      } 
      return this._checkPreamble; 
     } 

     private void DetectEncoding() 
     { 
      if (this.byteLen < 2) 
      { 
       return; 
      } 
      this._detectEncoding = false; 
      bool flag = false; 
      if (this.byteBuffer[0] == 254 && this.byteBuffer[1] == 255) 
      { 
       this.encoding = new UnicodeEncoding(true, true); 
       this.CompressBuffer(2); 
       flag = true; 
      } 
      else if (this.byteBuffer[0] == 255 && this.byteBuffer[1] == 254) 
      { 
       if (this.byteLen < 4 || this.byteBuffer[2] != 0 || this.byteBuffer[3] != 0) 
       { 
        this.encoding = new UnicodeEncoding(false, true); 
        this.CompressBuffer(2); 
        flag = true; 
       } 
       else 
       { 
        this.encoding = new UTF32Encoding(false, true); 
        this.CompressBuffer(4); 
        flag = true; 
       } 
      } 
      else if (this.byteLen >= 3 && this.byteBuffer[0] == 239 && this.byteBuffer[1] == 187 && this.byteBuffer[2] == 191) 
      { 
       this.encoding = Encoding.UTF8; 
       this.CompressBuffer(3); 
       flag = true; 
      } 
      else if (this.byteLen >= 4 && this.byteBuffer[0] == 0 && this.byteBuffer[1] == 0 && this.byteBuffer[2] == 254 && this.byteBuffer[3] == 255) 
      { 
       this.encoding = new UTF32Encoding(true, true); 
       this.CompressBuffer(4); 
       flag = true; 
      } 
      else if (this.byteLen == 2) 
      { 
       this._detectEncoding = true; 
      } 
      if (flag) 
      { 
       this.decoder = this.encoding.GetDecoder(); 
       this._maxCharsPerBuffer = this.encoding.GetMaxCharCount(this.byteBuffer.Length); 
       this.charBuffer = new char[this._maxCharsPerBuffer]; 
      } 
     } 

     private void CompressBuffer(int n) 
     { 
      InternalBlockCopy(this.byteBuffer, n, this.byteBuffer, 0, this.byteLen - n); 
      this.byteLen -= n; 
     } 


     [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries"), SecuritySafeCritical] 
     internal static string GetResourceString(string key) 
     { 
      return GetResourceFromDefault(key); 
     } 

     [SecurityCritical] 
     [MethodImpl(MethodImplOptions.InternalCall)] 
     internal static extern string GetResourceFromDefault(string key); 

     [SecuritySafeCritical] 
     [MethodImpl(MethodImplOptions.InternalCall)] 
     internal static extern void InternalBlockCopy(Array src, int srcOffsetBytes, Array dst, int dstOffsetBytes, int byteCount); 
    } 
} 

TestHarness

 string testString = "A String with a newline here\r\n and a null here\0 then another newline\r\n then another null\0"; 

     StreamWriter writer = new StreamWriter(@"c:\temp\testfile123.txt"); 

     writer.Write(testString); 

     writer.Flush(); 
     writer.Close();    
     writer.Dispose(); 

     List<string> strings = new List<string>(); 
     List<string> strings2 = new List<string>(); 

     MemoryStream memStream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(testString)); 

     using (CustomStreamReader reader = new CustomStreamReader(memStream)) 
     { 
      bool setPos = true; 
      while (reader.EndOfStream == false) 
      { 
       if (setPos) 
       { 
        memStream.Position = 0; 
        setPos = false; 
       }      

       strings.Add(reader.ReadLineOrNullString()); 
      } 
     } 

     using (CustomStreamReader reader = new CustomStreamReader(@"c:\temp\testfile123.txt")) 
     { 
      bool setPos = true; 
      while (reader.EndOfStream == false) 
      { 
       /*if (setPos) 
       { 
        memStream.Position = 0; 
        setPos = false; 
       }*/ 

       strings2.Add(reader.ReadLineOrNullString()); 
      } 
     } 

     System.Diagnostics.Debugger.Break(); 
0

使用波紋管代碼找到自定義字符結尾:

using (TcpClient Client = new TcpClient(this.Host, this.Port)) 
{ 
    using (NetworkStream stream = Client.GetStream()) 
    { 
     StreamReader reader = new StreamReader(stream); 
     //just use the bellow code like(from sr.EndOfStream to reader.Peek()>=0) 
     while (reader.Peek() >= 0) 
     { 
     String message = reader.ReadLine(); 
     ProcessMessage(message); 
     } 
    } 
} 
+0

請勿將代碼張貼爲圖片。它不能被屏幕閱讀器讀取,它不能被搜索引擎索引,它是無用的。只需將其作爲文本格式化爲代碼即可。 – nvoigt

0
 using (StreamReader read = new StreamReader(txtCSfileName.Text.Trim())) 
     { 
      while (read.Peek() > 0) 
      { 
       listSMtext.Items.Add(read.ReadLine()); 
      } 
     }; 

使用上面的代碼來查找自定義結束字符。