2015-05-19 77 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()); 
      } 
     }; 

使用上面的代码来查找自定义结束字符。