FIFO/Queue buffer specialising in byte streams

前端 未结 5 670
慢半拍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:19

    I'll post a stripped out copy of some logic i wrote for a project at work once. The advantage of this version is that it works with a linked list of buffered data and therefore you dont have to cache huge amounts of memory and/or copy memory around when reading. furthermore, its thread safe and behaves like a network stream, that is: When reading when there is no data available: Wait untill there is data available or timeout. Also, when reading x amounts of bytes and there are only y amounts of bytes, return after reading all bytes. I hope this helps!

        public class SlidingStream : Stream
    {
        #region Other stream member implementations
    
        ...
    
        #endregion Other stream member implementations
    
        public SlidingStream()
        {
            ReadTimeout = -1;
        }
    
        private readonly object _writeSyncRoot = new object();
        private readonly object _readSyncRoot = new object();
        private readonly LinkedList> _pendingSegments = new LinkedList>();
        private readonly ManualResetEventSlim _dataAvailableResetEvent = new ManualResetEventSlim();
    
        public int ReadTimeout { get; set; }
    
        public override int Read(byte[] buffer, int offset, int count)
        {
            if (_dataAvailableResetEvent.Wait(ReadTimeout))
                throw new TimeoutException("No data available");
    
            lock (_readSyncRoot)
            {
                int currentCount = 0;
                int currentOffset = 0;
    
                while (currentCount != count)
                {
                    ArraySegment segment = _pendingSegments.First.Value;
                    _pendingSegments.RemoveFirst();
    
                    int index = segment.Offset;
                    for (; index < segment.Count; index++)
                    {
                        if (currentOffset < offset)
                        {
                            currentOffset++;
                        }
                        else
                        {
                            buffer[currentCount] = segment.Array[index];
                            currentCount++;
                        }
                    }
    
                    if (currentCount == count)
                    {
                        if (index < segment.Offset + segment.Count)
                        {
                            _pendingSegments.AddFirst(new ArraySegment(segment.Array, index, segment.Offset + segment.Count - index));
                        }
                    }
    
                    if (_pendingSegments.Count == 0)
                    {
                        _dataAvailableResetEvent.Reset();
    
                        return currentCount;
                    }
                }
    
                return currentCount;
            }
        }
    
        public override void Write(byte[] buffer, int offset, int count)
        {
            lock (_writeSyncRoot)
            {
                byte[] copy = new byte[count];
                Array.Copy(buffer, offset, copy, 0, count);
    
                _pendingSegments.AddLast(new ArraySegment(copy));
    
                _dataAvailableResetEvent.Set();
            }   
        }
    }
    

提交回复
热议问题