FIFO/Queue buffer specialising in byte streams

前端 未结 5 682
慢半拍i
慢半拍i 2020-12-14 19:46

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

5条回答
  •  没有蜡笔的小新
    2020-12-14 20:02

    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]);
            }
        }
    }
    

提交回复
热议问题