Is there any .NET data structure/combination of classes that allows for byte data to be appended to the end of a buffer but all peeks and reads are from the start, shortenin
A late answer but there is a Queue support in .NET Framework since version 2.0. Use ConcurrentQueue for thread safe operations.
I created the below implementation of a Stream which will Read and ReadLines when the bytes become available. Not the best implementation but it should do the job.
public class QueueStream : Stream
{
protected readonly ConcurrentQueue Queue = new ConcurrentQueue();
public Task? DownloadTask { get; set; }
public override bool CanRead => true;
public override bool CanSeek => false;
public override bool CanWrite => true;
public override long Length => Queue.Count;
public override long Position
{
get => 0;
set => throw new NotImplementedException($"{nameof(QueueStream)} is not seekable");
}
public override void Flush()
{
Queue.Clear();
}
public override int Read(byte[] buffer, int offset, int count)
{
if (buffer == null)
{
throw new ArgumentNullException(nameof(buffer));
}
if (buffer.Length < count)
{
throw new Exception($"{nameof(buffer)} length is less that the specified {nameof(count)}");
}
var index = 0;
var insertedCount = 0;
while (Queue.TryDequeue(out var b) && insertedCount < count)
{
if (index >= offset)
{
buffer[insertedCount++] = b;
}
index++;
}
return insertedCount;
}
public string ReadLines(int numberOfLines = 1)
{
var currentLine = 0;
var stringBuilder = new StringBuilder();
Func isFaulted = () => false;
Func isCompleted = () => true;
if (DownloadTask != null)
{
isFaulted = () => DownloadTask.IsFaulted;
isCompleted = () => DownloadTask.IsCompleted;
}
while (!isFaulted() && !isCompleted() && currentLine < numberOfLines)
{
if (!Queue.TryDequeue(out var byteResult))
{
continue;
}
if (byteResult == '\r' || byteResult == '\n')
{
if (byteResult == '\r')
{
byte peekResult = 0;
while (!isFaulted() && !isCompleted() && !Queue.TryPeek(out peekResult))
{
}
if (peekResult == '\n')
{
Queue.TryDequeue(out _);
}
}
stringBuilder.Append(Environment.NewLine);
currentLine++;
continue;
}
stringBuilder.Append((char)byteResult);
}
return stringBuilder.ToString();
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotImplementedException();
}
public override void SetLength(long value)
{
throw new NotImplementedException();
}
public override void Write(byte[] buffer, int offset, int count)
{
var forEnd = offset + count;
for (var index = offset; index < forEnd; index++)
{
Queue.Enqueue(buffer[index]);
}
}
}