patterncsharpMinor
Extracting complete lines from a data stream
Viewed 0 times
streamcompleteextractingfromdatalines
Problem
When reading from the Console, it's very easy to get a complete line, you simply call
When reading from a
In order to simplify line extraction I've written a
The
Some unit tests:
```
using System;
using System.Collections.Generic;
using System.Collections;
using NUnit.Framework;
using MudCore.Connectio
Console.Readline. When reading from a
TCPClient there isn't an equivalent function. You can either read a byte at a time, or read a block (up to a maximum size) in which case an arbitrary amount of data will be returned depending how the network behaved.In order to simplify line extraction I've written a
LineBuffer class. It has an Append method that allows new blocks of data to be added to the buffer. Whenever a complete line is received, the action supplied via the constructor is called.The
LineBuffer class:using System;
using System.Text;
namespace MudCore.Connection
{
public class LineBuffer
{
private readonly Action _onLineFound;
private readonly StringBuilder _currentLine;
public LineBuffer(Action onLineFound)
{
_onLineFound = onLineFound;
_currentLine = new StringBuilder();
}
public void Append(string input)
{
if (input == null) return;
while (input.Contains("\n"))
{
var indexOfNewLine = input.IndexOf('\n');
var left = input.Substring(0, indexOfNewLine);
_currentLine.Append(left);
var line = _currentLine.Replace("\r","").ToString();
_currentLine.Clear();
if (indexOfNewLine != input.Length - 1)
{
input = input.Substring(indexOfNewLine + 1);
}
else
{
input = string.Empty;
}
_onLineFound.Invoke(line);
}
if (!string.IsNullOrEmpty(input))
{
_currentLine.Append(input);
}
}
}
}Some unit tests:
```
using System;
using System.Collections.Generic;
using System.Collections;
using NUnit.Framework;
using MudCore.Connectio
Solution
There are some alternatives that are built in, for example in the simplest form combine a
Which is unbuffered, if you want to add buffering in, just use a
These are pretty high performance because they operate at a lower level. Ideally you'd want to ditch the
NetworkStream with StreamReader:using (var netStream = new NetworkStream(tcpClient.Client))
using (var reader = new StreamReader(netStream))
{
var line = reader.ReadLine();
}Which is unbuffered, if you want to add buffering in, just use a
BufferedStream in the middle:using (var netStream = new NetworkStream(tcpClient.Client))
using (var bufferStream = new BufferedStream(netStream))
using (var reader = new StreamReader(bufferStream))
{
var line = reader.ReadLine();
}These are pretty high performance because they operate at a lower level. Ideally you'd want to ditch the
TcpClient and go direct with a Socket for best performance, but TcpClient.Client gives direct access to the underlying socket.Code Snippets
using (var netStream = new NetworkStream(tcpClient.Client))
using (var reader = new StreamReader(netStream))
{
var line = reader.ReadLine();
}using (var netStream = new NetworkStream(tcpClient.Client))
using (var bufferStream = new BufferedStream(netStream))
using (var reader = new StreamReader(bufferStream))
{
var line = reader.ReadLine();
}Context
StackExchange Code Review Q#147935, answer score: 4
Revisions (0)
No revisions yet.